@anysiteio/agent-skills 1.3.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.claude-plugin/marketplace.json +61 -1
  2. package/.claude-plugin/plugin.json +5 -1
  3. package/README.md +27 -33
  4. package/bin/install.js +186 -135
  5. package/bundles.json +19 -0
  6. package/package.json +3 -2
  7. package/skills/anysite-audience-analysis/SKILL.md +110 -38
  8. package/skills/anysite-audience-analysis/references/PLATFORM_COVERAGE.md +38 -19
  9. package/skills/anysite-audience-analysis/references/TOOL_MAPPING.md +16 -11
  10. package/skills/anysite-brand-reputation/SKILL.md +105 -43
  11. package/skills/anysite-competitor-analyzer/SKILL.md +170 -111
  12. package/skills/anysite-competitor-intelligence/SKILL.md +201 -116
  13. package/skills/anysite-competitor-intelligence/references/ANALYSIS_PATTERNS.md +17 -13
  14. package/skills/anysite-content-analytics/SKILL.md +101 -33
  15. package/skills/anysite-crm-account-brief/SKILL.md +71 -0
  16. package/skills/anysite-crm-audit/SKILL.md +59 -0
  17. package/skills/anysite-crm-champions/SKILL.md +76 -0
  18. package/skills/anysite-crm-competitor-intel/SKILL.md +74 -0
  19. package/skills/anysite-crm-enrich/SKILL.md +84 -0
  20. package/skills/anysite-crm-lookalikes/SKILL.md +64 -0
  21. package/skills/anysite-crm-prospect/SKILL.md +90 -0
  22. package/skills/anysite-crm-score/SKILL.md +72 -0
  23. package/skills/anysite-crm-setup/SKILL.md +147 -0
  24. package/skills/anysite-crm-signals/SKILL.md +96 -0
  25. package/skills/anysite-influencer-discovery/SKILL.md +123 -71
  26. package/skills/anysite-lead-generation/SKILL.md +288 -256
  27. package/skills/anysite-lead-generation/references/LINKEDIN_STRATEGIES.md +79 -71
  28. package/skills/anysite-lead-generation/references/WEB_SCRAPING.md +121 -87
  29. package/skills/anysite-market-research/SKILL.md +117 -68
  30. package/skills/anysite-mcp/SKILL.md +128 -0
  31. package/skills/anysite-mcp-migration/SKILL.md +290 -0
  32. package/skills/anysite-person-analyzer/SKILL.md +86 -53
  33. package/skills/anysite-trend-analysis/SKILL.md +119 -55
  34. package/skills/anysite-vc-analyst/SKILL.md +12 -2
  35. package/skills/competitor-discovery/SKILL.md +350 -0
  36. package/skills/customer-pain-mining/SKILL.md +318 -0
  37. package/skills/positioning-map/SKILL.md +314 -0
@@ -1,6 +1,6 @@
1
1
  # Web Scraping for Contact Extraction
2
2
 
3
- Strategies and techniques for extracting contact information from company websites using anysite MCP.
3
+ Strategies and techniques for extracting contact information from company websites using anysite MCP v2.
4
4
 
5
5
  ## Overview
6
6
 
@@ -13,18 +13,20 @@ Web scraping complements LinkedIn lead generation by:
13
13
 
14
14
  ## Contact Extraction Tools
15
15
 
16
- ### parse_webpage
16
+ ### Web Page Parsing (v2)
17
17
 
18
18
  Primary tool for extracting contacts from web pages.
19
19
 
20
+ **v2 Call**: `execute("webparser", "parse", "parse", {"url": ..., "extract_contacts": true})`
21
+
20
22
  **Basic Usage**:
21
23
  ```
22
- Tool: mcp__anysite__parse_webpage
24
+ Tool: mcp__anysite__execute
23
25
  Parameters:
24
- - url: "https://company.com/contact"
25
- - extract_contacts: true
26
- - strip_all_tags: true
27
- - only_main_content: true
26
+ - source: "webparser"
27
+ - category: "parse"
28
+ - endpoint: "parse"
29
+ - params: {"url": "https://company.com/contact", "extract_contacts": true, "strip_all_tags": true, "only_main_content": true}
28
30
  ```
29
31
 
30
32
  **Returns**:
@@ -32,22 +34,34 @@ Parameters:
32
34
  - Phones: Phone numbers in various formats
33
35
  - Social links: LinkedIn, Twitter, Facebook, Instagram
34
36
  - Content: Page text for additional parsing
37
+ - `cache_key`: For use with query_cache and export_data
35
38
 
36
39
  **Best Practices**:
37
40
  - Set `extract_contacts: true` to enable contact extraction
38
41
  - Use `only_main_content: true` to avoid footer/header noise
39
42
  - Try multiple page variations (/contact, /about, /team)
40
43
 
41
- ### get_sitemap
44
+ ### Sitemap Parsing (v2)
42
45
 
43
46
  Discover all pages on a website to find contact information.
44
47
 
48
+ **v2 Call**: `discover("webparser", "parse")` to find the sitemap endpoint, then `execute(...)` with discovered endpoint and params.
49
+
45
50
  **Basic Usage**:
46
51
  ```
47
- Tool: mcp__anysite__get_sitemap
52
+ Step 1: Discover sitemap endpoint
53
+ Tool: mcp__anysite__discover
54
+ Parameters:
55
+ - source: "webparser"
56
+ - category: "parse"
57
+
58
+ Step 2: Execute with discovered endpoint
59
+ Tool: mcp__anysite__execute
48
60
  Parameters:
49
- - url: "https://company.com"
50
- - count: 100
61
+ - source: "webparser"
62
+ - category: "parse"
63
+ - endpoint: <discovered_sitemap_endpoint>
64
+ - params: {"url": "https://company.com", "count": 100}
51
65
  ```
52
66
 
53
67
  **Returns**:
@@ -58,7 +72,7 @@ Parameters:
58
72
  **Best Practices**:
59
73
  - Start with count=100 to get comprehensive coverage
60
74
  - Filter results for relevant pages (contact, team, about, leadership)
61
- - Parse identified pages with parse_webpage
75
+ - Parse identified pages with execute("webparser", "parse", "parse", ...)
62
76
 
63
77
  ## Common Page Patterns
64
78
 
@@ -84,7 +98,7 @@ Parameters:
84
98
 
85
99
  **Example**:
86
100
  ```
87
- parse_webpage("https://company.com/contact", extract_contacts=true)
101
+ execute("webparser", "parse", "parse", {"url": "https://company.com/contact", "extract_contacts": true})
88
102
 
89
103
  Expected data:
90
104
  - General company email (info@, contact@, hello@)
@@ -115,7 +129,7 @@ Expected data:
115
129
 
116
130
  **Example**:
117
131
  ```
118
- parse_webpage("https://company.com/about", extract_contacts=true)
132
+ execute("webparser", "parse", "parse", {"url": "https://company.com/about", "extract_contacts": true})
119
133
 
120
134
  Expected data:
121
135
  - Leadership emails
@@ -147,7 +161,7 @@ Expected data:
147
161
 
148
162
  **Example**:
149
163
  ```
150
- parse_webpage("https://company.com/team", extract_contacts=true)
164
+ execute("webparser", "parse", "parse", {"url": "https://company.com/team", "extract_contacts": true})
151
165
 
152
166
  Expected data:
153
167
  - Individual names and titles
@@ -177,7 +191,7 @@ Expected data:
177
191
 
178
192
  **Example**:
179
193
  ```
180
- parse_webpage("https://company.com/locations", extract_contacts=true)
194
+ execute("webparser", "parse", "parse", {"url": "https://company.com/locations", "extract_contacts": true})
181
195
 
182
196
  Expected data:
183
197
  - Office-specific emails
@@ -331,11 +345,14 @@ Extracted:
331
345
 
332
346
  1. **Get sitemap**
333
347
  ```
334
- get_sitemap("https://company.com", count=100)
348
+ discover("webparser", "parse") -> find sitemap endpoint -> execute(...)
335
349
  ```
336
350
 
337
351
  2. **Filter for relevant pages**
338
352
  ```
353
+ Use query_cache on sitemap results:
354
+ query_cache(cache_key, conditions=[{"field": "url", "operator": "contains", "value": "contact"}])
355
+
339
356
  Filter sitemap results for:
340
357
  - URLs containing: contact, about, team, location, office
341
358
  - Exclude: blog, news, privacy, terms
@@ -344,7 +361,7 @@ Filter sitemap results for:
344
361
  3. **Parse each relevant page**
345
362
  ```
346
363
  For each filtered URL:
347
- parse_webpage(url, extract_contacts=true)
364
+ execute("webparser", "parse", "parse", {"url": "<url>", "extract_contacts": true})
348
365
  ```
349
366
 
350
367
  4. **Consolidate and deduplicate**
@@ -359,8 +376,13 @@ For each filtered URL:
359
376
  5. **Enrich with LinkedIn**
360
377
  ```
361
378
  For team member names found:
362
- search_linkedin_users(first_name, last_name, company_keywords)
363
- get_linkedin_profile(user)
379
+ execute("linkedin", "search", "search_users", {"first_name": "<first>", "last_name": "<last>", "company_keywords": "<company>"})
380
+ execute("linkedin", "user", "get", {"user": "<username>"})
381
+ ```
382
+
383
+ 6. **Export results**
384
+ ```
385
+ export_data(cache_key, "csv") -> Download URL for consolidated contacts
364
386
  ```
365
387
 
366
388
  **Expected Output**:
@@ -379,18 +401,18 @@ For team member names found:
379
401
  1. **Find team page**
380
402
  ```
381
403
  Try common patterns:
382
- - parse_webpage("https://company.com/team")
383
- - parse_webpage("https://company.com/about/team")
384
- - parse_webpage("https://company.com/people")
404
+ - execute("webparser", "parse", "parse", {"url": "https://company.com/team"})
405
+ - execute("webparser", "parse", "parse", {"url": "https://company.com/about/team"})
406
+ - execute("webparser", "parse", "parse", {"url": "https://company.com/people"})
385
407
 
386
408
  Or use sitemap:
387
- - get_sitemap("https://company.com", count=100)
409
+ - discover("webparser", "parse") -> find sitemap endpoint -> execute(...)
388
410
  - Filter for "team" or "people"
389
411
  ```
390
412
 
391
413
  2. **Extract team members**
392
414
  ```
393
- parse_webpage(team_url, extract_contacts=true)
415
+ execute("webparser", "parse", "parse", {"url": "<team_url>", "extract_contacts": true})
394
416
 
395
417
  Look for patterns:
396
418
  - Name + Title combinations
@@ -405,25 +427,25 @@ Some team pages link to individual profiles:
405
427
  - /team/john-smith
406
428
  - /people/jane-doe
407
429
 
408
- parse_webpage(individual_url, extract_contacts=true)
409
- Often has direct email, phone
430
+ execute("webparser", "parse", "parse", {"url": "<individual_url>", "extract_contacts": true})
431
+ -> Often has direct email, phone
410
432
  ```
411
433
 
412
434
  4. **Match to LinkedIn**
413
435
  ```
414
436
  For each team member name:
415
- search_linkedin_users(
416
- first_name=<first>,
417
- last_name=<last>,
418
- company_keywords=<company>
419
- )
437
+ execute("linkedin", "search", "search_users", {
438
+ "first_name": "<first>",
439
+ "last_name": "<last>",
440
+ "company_keywords": "<company>"
441
+ })
420
442
  ```
421
443
 
422
444
  5. **Construct email addresses**
423
445
  ```
424
446
  If email pattern detected from some team members:
425
447
  - Apply pattern to all team members
426
- - Example: john.doe@company.com jane.smith@company.com
448
+ - Example: john.doe@company.com -> jane.smith@company.com
427
449
  ```
428
450
 
429
451
  **Expected Output**:
@@ -440,7 +462,7 @@ If email pattern detected from some team members:
440
462
 
441
463
  1. **Find locations page**
442
464
  ```
443
- parse_webpage("https://company.com/locations", extract_contacts=true)
465
+ execute("webparser", "parse", "parse", {"url": "https://company.com/locations", "extract_contacts": true})
444
466
  ```
445
467
 
446
468
  2. **Extract location information**
@@ -459,17 +481,17 @@ Some companies have per-location pages:
459
481
  - /locations/san-francisco
460
482
  - /offices/new-york
461
483
 
462
- parse_webpage(location_url, extract_contacts=true)
484
+ execute("webparser", "parse", "parse", {"url": "<location_url>", "extract_contacts": true})
463
485
  ```
464
486
 
465
487
  4. **Find office leaders**
466
488
  ```
467
489
  For each location:
468
- search_linkedin_users(
469
- title="Office Manager OR General Manager",
470
- company_keywords=<company>,
471
- location=<office_city>
472
- )
490
+ execute("linkedin", "search", "search_users", {
491
+ "title": "Office Manager OR General Manager",
492
+ "company_keywords": "<company>",
493
+ "location": "<office_city>"
494
+ })
473
495
  ```
474
496
 
475
497
  5. **Build location contact sheet**
@@ -481,6 +503,8 @@ Spreadsheet with:
481
503
  - Local email
482
504
  - Office manager name + LinkedIn
483
505
  - Office manager email
506
+
507
+ Export via: export_data(cache_key, "csv")
484
508
  ```
485
509
 
486
510
  **Expected Output**:
@@ -591,7 +615,7 @@ YouTube: youtube.com/[company]
591
615
 
592
616
  **Parsing Strategy**:
593
617
  ```
594
- parse_webpage(url, extract_contacts=true) returns social links
618
+ execute("webparser", "parse", "parse", {"url": "<url>", "extract_contacts": true}) returns social links
595
619
 
596
620
  Use social profiles to:
597
621
  1. Verify company information
@@ -607,8 +631,8 @@ Social links found:
607
631
  - Twitter: twitter.com/techcorp
608
632
 
609
633
  Next steps:
610
- get_linkedin_company("techcorp") Company details
611
- get_twitter_user("techcorp") Twitter profile
634
+ execute("linkedin", "company", "get", {"company": "techcorp"}) -> Company details
635
+ execute("twitter", "user", "get", {"username": "techcorp"}) -> Twitter profile
612
636
  ```
613
637
 
614
638
  ## Error Handling & Troubleshooting
@@ -617,7 +641,7 @@ get_twitter_user("techcorp") → Twitter profile
617
641
 
618
642
  #### 1. No Contacts Found
619
643
 
620
- **Symptoms**: parse_webpage returns no emails or phones
644
+ **Symptoms**: execute() returns no emails or phones
621
645
 
622
646
  **Causes**:
623
647
  - JavaScript-rendered content (page loads dynamically)
@@ -639,6 +663,8 @@ get_twitter_user("techcorp") → Twitter profile
639
663
  - Annual report might list executives
640
664
 
641
665
  4. Use LinkedIn as primary source instead
666
+
667
+ 5. Check llm_hint in response for guidance
642
668
  ```
643
669
 
644
670
  #### 2. Malformed Contact Data
@@ -682,22 +708,23 @@ Extension: "123"
682
708
  **Solutions**:
683
709
  ```
684
710
  Filtering strategy:
685
- 1. only_main_content: true (remove footer/header)
711
+ 1. Use only_main_content: true in params (remove footer/header)
686
712
  2. Verify email domain matches company domain
687
713
  3. Exclude common spam patterns (noreply@, donotreply@)
688
714
  4. Filter out tracking/marketing emails
715
+ 5. Use query_cache() to filter results after fetching
689
716
  ```
690
717
 
691
718
  **Example Filter**:
692
719
  ```
693
720
  Keep:
694
- - john@company.com
695
- - sales@company.com
721
+ - john@company.com
722
+ - sales@company.com
696
723
 
697
724
  Discard:
698
- - noreply@company.com
699
- - partner@otherdomain.com
700
- - ads@advertising-network.com
725
+ - noreply@company.com
726
+ - partner@otherdomain.com
727
+ - ads@advertising-network.com
701
728
  ```
702
729
 
703
730
  #### 4. Rate Limiting or Blocking
@@ -711,16 +738,16 @@ Discard:
711
738
 
712
739
  **Solutions**:
713
740
  ```
714
- 1. Increase request_timeout parameter
715
- 2. Add delays between requests (30-60 seconds)
716
- 3. Rotate user agents (handled by MCP server)
717
- 4. Scrape during off-peak hours
718
- 5. Use smaller batch sizes
741
+ 1. Add delays between requests (30-60 seconds)
742
+ 2. Rotate user agents (handled by MCP server)
743
+ 3. Scrape during off-peak hours
744
+ 4. Use smaller batch sizes
745
+ 5. Check llm_hint in error response for specific guidance
719
746
  ```
720
747
 
721
748
  **Best Practices**:
722
749
  ```
723
- - Wait 30-60 seconds between parse_webpage calls
750
+ - Wait 30-60 seconds between execute() calls for the same domain
724
751
  - Process 5-10 websites per batch
725
752
  - Don't scrape same site multiple times rapidly
726
753
  - Respect robots.txt
@@ -730,22 +757,22 @@ Discard:
730
757
 
731
758
  **Email Validation Checklist**:
732
759
  ```
733
- Contains @ symbol
734
- Has valid domain extension
735
- Domain matches company website
736
- Not a role-based email (noreply, admin, etc.)
737
- Proper format (no spaces, special chars)
738
- Not a personal email (gmail, yahoo, etc. for B2B)
760
+ - Contains @ symbol
761
+ - Has valid domain extension
762
+ - Domain matches company website
763
+ - Not a role-based email (noreply, admin, etc.)
764
+ - Proper format (no spaces, special chars)
765
+ - Not a personal email (gmail, yahoo, etc. for B2B)
739
766
  ```
740
767
 
741
768
  **Phone Validation Checklist**:
742
769
  ```
743
- Contains correct number of digits for region
744
- Has valid area/city code
745
- Not a fax number
746
- Not a toll-free number (for direct contact)
747
- Matches expected country code
748
- Includes extension if available
770
+ - Contains correct number of digits for region
771
+ - Has valid area/city code
772
+ - Not a fax number
773
+ - Not a toll-free number (for direct contact)
774
+ - Matches expected country code
775
+ - Includes extension if available
749
776
  ```
750
777
 
751
778
  **Data Quality Scoring**:
@@ -772,7 +799,7 @@ Poor Quality (<50):
772
799
 
773
800
  ## Integration with LinkedIn Data
774
801
 
775
- ### Workflow: LinkedIn Web Enrichment
802
+ ### Workflow: LinkedIn -> Web Enrichment
776
803
 
777
804
  **Pattern**: Use LinkedIn as source, enrich with web data
778
805
 
@@ -780,21 +807,21 @@ Poor Quality (<50):
780
807
 
781
808
  1. **Find prospects on LinkedIn**
782
809
  ```
783
- search_linkedin_users(title, location, company_keywords)
810
+ execute("linkedin", "search", "search_users", {"title": "<title>", "location": "<location>", "company_keywords": "<company>"})
784
811
  ```
785
812
 
786
813
  2. **Get company websites**
787
814
  ```
788
815
  For each prospect:
789
- get_linkedin_company(prospect.company)
790
- Extract website URL
816
+ execute("linkedin", "company", "get", {"company": "<prospect.company>"})
817
+ -> Extract website URL
791
818
  ```
792
819
 
793
820
  3. **Extract company contacts**
794
821
  ```
795
822
  For each company website:
796
- parse_webpage(website + "/contact", extract_contacts=true)
797
- parse_webpage(website + "/team", extract_contacts=true)
823
+ execute("webparser", "parse", "parse", {"url": "<website>/contact", "extract_contacts": true})
824
+ execute("webparser", "parse", "parse", {"url": "<website>/team", "extract_contacts": true})
798
825
  ```
799
826
 
800
827
  4. **Match web contacts to LinkedIn**
@@ -803,7 +830,7 @@ For each email found on website:
803
830
  If email pattern matches prospect name:
804
831
  Assign email to LinkedIn prospect
805
832
  Else:
806
- Try find_linkedin_user_email(email)
833
+ Try execute("linkedin", "email", "find", {"user": "<prospect>"})
807
834
  ```
808
835
 
809
836
  5. **Build enriched prospect list**
@@ -813,6 +840,8 @@ Combine:
813
840
  - Company website (phone, address)
814
841
  - Direct email (from web or LinkedIn)
815
842
  - Social profiles (from website)
843
+
844
+ Export via: export_data(cache_key, "csv")
816
845
  ```
817
846
 
818
847
  **Expected Result**:
@@ -821,7 +850,7 @@ Combine:
821
850
  - Verified company websites
822
851
  - Full contact profiles ready for outreach
823
852
 
824
- ### Workflow: Web LinkedIn Validation
853
+ ### Workflow: Web -> LinkedIn Validation
825
854
 
826
855
  **Pattern**: Use website as source, validate with LinkedIn
827
856
 
@@ -829,27 +858,27 @@ Combine:
829
858
 
830
859
  1. **Extract team from website**
831
860
  ```
832
- parse_webpage("https://company.com/team", extract_contacts=true)
833
- Get names, titles, emails
861
+ execute("webparser", "parse", "parse", {"url": "https://company.com/team", "extract_contacts": true})
862
+ -> Get names, titles, emails
834
863
  ```
835
864
 
836
865
  2. **Search LinkedIn for each person**
837
866
  ```
838
867
  For each team member:
839
- search_linkedin_users(
840
- first_name=<first>,
841
- last_name=<last>,
842
- company_keywords=<company>
843
- )
868
+ execute("linkedin", "search", "search_users", {
869
+ "first_name": "<first>",
870
+ "last_name": "<last>",
871
+ "company_keywords": "<company>"
872
+ })
844
873
  ```
845
874
 
846
875
  3. **Validate and enrich**
847
876
  ```
848
877
  For each LinkedIn match:
849
- get_linkedin_profile(user)
850
- Verify title matches
851
- Get full work history
852
- Find additional contact methods
878
+ execute("linkedin", "user", "get", {"user": "<username>"})
879
+ -> Verify title matches
880
+ -> Get full work history
881
+ -> Find additional contact methods
853
882
  ```
854
883
 
855
884
  4. **Cross-reference data**
@@ -867,6 +896,8 @@ Keep prospects where:
867
896
  - Title matches (or is recent)
868
897
  - Still at company
869
898
  - Email validated
899
+
900
+ Export via: export_data(cache_key, "csv")
870
901
  ```
871
902
 
872
903
  **Expected Result**:
@@ -883,6 +914,8 @@ Keep prospects where:
883
914
  2. **Parse in batches** of 5-10 websites at a time
884
915
  3. **Prioritize high-value pages** (team, leadership) over generic contact pages
885
916
  4. **Use LinkedIn first** for individual contacts, web scraping for company-level contacts
917
+ 5. **Use get_page()** to paginate through large result sets without re-executing
918
+ 6. **Use query_cache()** to filter and sort already-fetched data without new API calls
886
919
 
887
920
  ### Quality
888
921
 
@@ -904,6 +937,7 @@ Keep prospects where:
904
937
  2. **Date stamp extractions** to know data freshness
905
938
  3. **Deduplicate systematically** (same email from multiple pages)
906
939
  4. **Categorize contacts** (by department, location, role)
940
+ 5. **Export via export_data()** for permanent records and team sharing
907
941
 
908
942
  ---
909
943