cited-cli 0.3.3__tar.gz → 0.3.4__tar.gz

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 (112) hide show
  1. {cited_cli-0.3.3 → cited_cli-0.3.4}/PKG-INFO +4 -4
  2. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/core/pyproject.toml +1 -1
  3. cited_cli-0.3.4/packages/core/src/cited_core/__init__.py +1 -0
  4. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/README.md +5 -0
  5. cited_cli-0.3.4/packages/mcp/SKILL.md +54 -0
  6. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/pyproject.toml +2 -2
  7. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/tools/audit.py +37 -9
  8. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/tools/auth.py +29 -8
  9. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/tools/business.py +29 -7
  10. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/tools/job.py +5 -1
  11. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/tools/recommend.py +21 -5
  12. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/tools/solution.py +17 -4
  13. {cited_cli-0.3.3 → cited_cli-0.3.4}/pyproject.toml +4 -4
  14. {cited_cli-0.3.3 → cited_cli-0.3.4}/scripts/deploy-mcp.sh +179 -32
  15. {cited_cli-0.3.3 → cited_cli-0.3.4}/scripts/release.sh +4 -2
  16. cited_cli-0.3.3/packages/core/src/cited_core/__init__.py +0 -1
  17. {cited_cli-0.3.3 → cited_cli-0.3.4}/.github/workflows/ci.yml +0 -0
  18. {cited_cli-0.3.3 → cited_cli-0.3.4}/.github/workflows/release.yml +0 -0
  19. {cited_cli-0.3.3 → cited_cli-0.3.4}/.gitignore +0 -0
  20. {cited_cli-0.3.3 → cited_cli-0.3.4}/CLAUDE.md +0 -0
  21. {cited_cli-0.3.3 → cited_cli-0.3.4}/DEMO.md +0 -0
  22. {cited_cli-0.3.3 → cited_cli-0.3.4}/FUTURE.md +0 -0
  23. {cited_cli-0.3.3 → cited_cli-0.3.4}/LICENSE +0 -0
  24. {cited_cli-0.3.3 → cited_cli-0.3.4}/README.md +0 -0
  25. {cited_cli-0.3.3 → cited_cli-0.3.4}/TEST_RUNBOOK.md +0 -0
  26. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/.claude-plugin/marketplace.json +0 -0
  27. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/.claude-plugin/plugin.json +0 -0
  28. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/.mcp.json +0 -0
  29. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/CLAUDE_DESKTOP_SETUP.md +0 -0
  30. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/agents/geo-analyst.md +0 -0
  31. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/commands/audit.md +0 -0
  32. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/commands/recommend.md +0 -0
  33. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/commands/status.md +0 -0
  34. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/settings.json +0 -0
  35. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/skills/business-setup/SKILL.md +0 -0
  36. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/skills/geo-audit/SKILL.md +0 -0
  37. {cited_cli-0.3.3 → cited_cli-0.3.4}/cited-plugins/skills/geo-recommend/SKILL.md +0 -0
  38. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/core/src/cited_core/api/__init__.py +0 -0
  39. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/core/src/cited_core/api/client.py +0 -0
  40. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/core/src/cited_core/api/endpoints.py +0 -0
  41. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/core/src/cited_core/auth/__init__.py +0 -0
  42. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/core/src/cited_core/auth/oauth_server.py +0 -0
  43. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/core/src/cited_core/auth/store.py +0 -0
  44. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/core/src/cited_core/config/__init__.py +0 -0
  45. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/core/src/cited_core/config/constants.py +0 -0
  46. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/core/src/cited_core/config/manager.py +0 -0
  47. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/core/src/cited_core/errors.py +0 -0
  48. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/Dockerfile +0 -0
  49. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/__init__.py +0 -0
  50. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/__main__.py +0 -0
  51. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/auth_provider.py +0 -0
  52. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/context.py +0 -0
  53. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/remote.py +0 -0
  54. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/server.py +0 -0
  55. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/tools/__init__.py +0 -0
  56. {cited_cli-0.3.3 → cited_cli-0.3.4}/packages/mcp/src/cited_mcp/tools/_helpers.py +0 -0
  57. {cited_cli-0.3.3 → cited_cli-0.3.4}/scripts/cleanup_dev.py +0 -0
  58. {cited_cli-0.3.3 → cited_cli-0.3.4}/scripts/dev-install.sh +0 -0
  59. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/__init__.py +0 -0
  60. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/__main__.py +0 -0
  61. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/api/__init__.py +0 -0
  62. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/api/client.py +0 -0
  63. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/api/endpoints.py +0 -0
  64. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/app.py +0 -0
  65. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/auth/__init__.py +0 -0
  66. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/auth/oauth_server.py +0 -0
  67. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/auth/store.py +0 -0
  68. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/__init__.py +0 -0
  69. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/agent.py +0 -0
  70. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/analytics.py +0 -0
  71. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/audit.py +0 -0
  72. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/auth.py +0 -0
  73. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/business.py +0 -0
  74. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/config_cmd.py +0 -0
  75. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/hq.py +0 -0
  76. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/job.py +0 -0
  77. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/mcp_cmd.py +0 -0
  78. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/named_audit.py +0 -0
  79. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/recommend.py +0 -0
  80. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/commands/solution.py +0 -0
  81. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/config/__init__.py +0 -0
  82. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/config/constants.py +0 -0
  83. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/config/manager.py +0 -0
  84. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/mcp/__init__.py +0 -0
  85. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/mcp/context.py +0 -0
  86. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/mcp/server.py +0 -0
  87. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/mcp/tools/__init__.py +0 -0
  88. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/mcp/tools/_helpers.py +0 -0
  89. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/mcp/tools/audit.py +0 -0
  90. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/mcp/tools/auth.py +0 -0
  91. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/mcp/tools/business.py +0 -0
  92. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/mcp/tools/job.py +0 -0
  93. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/mcp/tools/recommend.py +0 -0
  94. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/mcp/tools/solution.py +0 -0
  95. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/output/__init__.py +0 -0
  96. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/output/formatter.py +0 -0
  97. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/output/progress.py +0 -0
  98. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/output/tables.py +0 -0
  99. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/utils/__init__.py +0 -0
  100. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/utils/errors.py +0 -0
  101. {cited_cli-0.3.3 → cited_cli-0.3.4}/src/cited_cli/utils/interactive.py +0 -0
  102. {cited_cli-0.3.3 → cited_cli-0.3.4}/tests/__init__.py +0 -0
  103. {cited_cli-0.3.3 → cited_cli-0.3.4}/tests/conftest.py +0 -0
  104. {cited_cli-0.3.3 → cited_cli-0.3.4}/tests/test_api_client.py +0 -0
  105. {cited_cli-0.3.3 → cited_cli-0.3.4}/tests/test_auth.py +0 -0
  106. {cited_cli-0.3.3 → cited_cli-0.3.4}/tests/test_config.py +0 -0
  107. {cited_cli-0.3.3 → cited_cli-0.3.4}/tests/test_live_pipeline.py +0 -0
  108. {cited_cli-0.3.3 → cited_cli-0.3.4}/tests/test_mcp_server.py +0 -0
  109. {cited_cli-0.3.3 → cited_cli-0.3.4}/tests/test_mcp_tools.py +0 -0
  110. {cited_cli-0.3.3 → cited_cli-0.3.4}/tests/test_output.py +0 -0
  111. {cited_cli-0.3.3 → cited_cli-0.3.4}/tests/test_pipeline.py +0 -0
  112. {cited_cli-0.3.3 → cited_cli-0.3.4}/tests/test_version.py +0 -0
@@ -1,22 +1,22 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cited-cli
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: CLI for the Cited GEO platform
5
5
  Author-email: Cited <support@youcited.com>
6
6
  License-Expression: LicenseRef-Proprietary
7
7
  License-File: LICENSE
8
8
  Requires-Python: >=3.11
9
- Requires-Dist: cited-core>=0.3.3
9
+ Requires-Dist: cited-core>=0.3.4
10
10
  Requires-Dist: rich>=13.0.0
11
11
  Requires-Dist: typer>=0.15.0
12
12
  Provides-Extra: dev
13
- Requires-Dist: cited-mcp>=0.3.3; extra == 'dev'
13
+ Requires-Dist: cited-mcp>=0.3.4; extra == 'dev'
14
14
  Requires-Dist: mypy>=1.10; extra == 'dev'
15
15
  Requires-Dist: pytest>=8.0; extra == 'dev'
16
16
  Requires-Dist: respx>=0.21; extra == 'dev'
17
17
  Requires-Dist: ruff>=0.4; extra == 'dev'
18
18
  Provides-Extra: mcp
19
- Requires-Dist: cited-mcp>=0.3.3; extra == 'mcp'
19
+ Requires-Dist: cited-mcp>=0.3.4; extra == 'mcp'
20
20
  Description-Content-Type: text/markdown
21
21
 
22
22
  # Cited CLI
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cited-core"
7
- version = "0.3.3"
7
+ version = "0.3.4"
8
8
  description = "Core library for the Cited GEO platform"
9
9
  license = "LicenseRef-Proprietary"
10
10
  requires-python = ">=3.11"
@@ -0,0 +1 @@
1
+ __version__ = "0.3.4"
@@ -101,6 +101,7 @@ cited-mcp-remote
101
101
  |------|-------------|
102
102
  | `check_auth_status` | Check current authentication status |
103
103
  | `login` | Authenticate via browser OAuth flow |
104
+ | `logout` | Clear stored authentication token |
104
105
 
105
106
  ### Businesses
106
107
  | Tool | Description |
@@ -194,6 +195,10 @@ ruff check packages/mcp/
194
195
  mypy packages/mcp/src --ignore-missing-imports
195
196
  ```
196
197
 
198
+ ## Privacy Policy
199
+
200
+ See our [Privacy Policy](https://youcited.com/privacy) for details on data collection, usage, storage, and third-party sharing.
201
+
197
202
  ## License
198
203
 
199
204
  Proprietary — see [youcited.com](https://youcited.com) for terms.
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: cited
3
+ description: Audit, optimize, and monitor your business's visibility in AI-powered search engines
4
+ ---
5
+
6
+ # Cited — AI Search Visibility Platform
7
+
8
+ Cited helps businesses measure and improve how they appear in AI-powered search results from ChatGPT, Claude, Perplexity, and Gemini. Use these tools to run GEO (Generative Engine Optimization) audits, get actionable recommendations, and generate ready-to-deploy solutions.
9
+
10
+ ## Core Workflow
11
+
12
+ The typical flow is: **Business Setup → Audit → Recommendations → Solutions**
13
+
14
+ ### 1. Business Setup
15
+ - `check_auth_status` — Verify authentication and check plan limits
16
+ - `list_businesses` — See existing businesses
17
+ - `create_business` — Add a new business (requires name, website, description)
18
+ - `crawl_business` — Crawl the business website to gather data for analysis
19
+
20
+ ### 2. Run an Audit
21
+ - `create_audit_template` — Define what questions to audit (e.g., "What is [business]?", "Best [industry] tools")
22
+ - `start_audit` — Launch the audit using a template
23
+ - `get_audit_status` — Poll until the audit completes (typically 2-4 minutes)
24
+ - `get_audit_result` — Retrieve visibility scores, citation rates, and competitor data
25
+
26
+ ### 3. Generate Recommendations
27
+ - `start_recommendation` — Analyze audit results and generate improvement recommendations
28
+ - `get_recommendation_insights` — Get structured insights with question-level analysis, competitor head-to-head comparisons, and strengthening tips. Each insight includes `source_type` and `source_id` needed for the next step.
29
+
30
+ ### 4. Create Solutions
31
+ - `start_solution` — Generate implementation artifacts (schema markup, content templates, outreach playbooks) for a specific insight
32
+ - `get_solution_result` — Retrieve the solution with downloadable artifacts
33
+
34
+ ## Example Prompts
35
+
36
+ **Run a full GEO audit:**
37
+ > "List my businesses, then run a GEO audit on [business name]. When it's done, show me my visibility scores and which competitors are being cited instead of me."
38
+
39
+ **Competitive analysis:**
40
+ > "Run an audit on my business for these questions: 'Best CRM software for small business', 'Top sales automation tools', 'What is [my product]?'. Then generate recommendations and show me the head-to-head comparisons with my top competitors."
41
+
42
+ **Generate solutions:**
43
+ > "Look at my latest audit recommendations and generate solutions for the top 3 highest-risk insights. I want to see the schema markup and content changes I need to make."
44
+
45
+ **Monitor over time:**
46
+ > "Show me the health scores for my business and compare them to my last audit. What has improved and what still needs work?"
47
+
48
+ ## Tips
49
+
50
+ - Always call `check_auth_status` first to verify authentication and plan limits
51
+ - Audits take 2-4 minutes — poll `get_audit_status` every 15 seconds
52
+ - Use `get_recommendation_insights` (not `get_recommendation_result`) for structured, actionable data
53
+ - Solutions have a concurrency limit of 3 — wait for one batch to complete before starting more
54
+ - Each insight's `source_type` and `source_id` map directly to `start_solution` parameters
@@ -4,14 +4,14 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cited-mcp"
7
- version = "0.3.3"
7
+ version = "0.3.4"
8
8
  description = "MCP server for the Cited GEO platform"
9
9
  readme = "README.md"
10
10
  license = "LicenseRef-Proprietary"
11
11
  requires-python = ">=3.11"
12
12
  authors = [{ name = "Cited", email = "support@youcited.com" }]
13
13
  dependencies = [
14
- "cited-core>=0.3.3",
14
+ "cited-core>=0.3.4",
15
15
  "mcp>=1.26.0",
16
16
  "PyJWT>=2.8.0",
17
17
  ]
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import Any
4
4
 
5
5
  from mcp.server.fastmcp import Context
6
+ from mcp.types import ToolAnnotations
6
7
 
7
8
  from cited_core.api import endpoints
8
9
  from cited_core.errors import CitedAPIError
@@ -11,7 +12,10 @@ from cited_mcp.server import mcp
11
12
  from cited_mcp.tools._helpers import _api_error_response, _auth_check, _get_ctx
12
13
 
13
14
 
14
- @mcp.tool()
15
+ @mcp.tool(
16
+ title="List Audit Templates",
17
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
18
+ )
15
19
  async def list_audit_templates(
16
20
  ctx: Context[Any, CitedContext, Any],
17
21
  business_id: str | None = None,
@@ -34,7 +38,10 @@ async def list_audit_templates(
34
38
  return _api_error_response(e)
35
39
 
36
40
 
37
- @mcp.tool()
41
+ @mcp.tool(
42
+ title="Get Audit Template",
43
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
44
+ )
38
45
  async def get_audit_template(ctx: Context[Any, CitedContext, Any], named_audit_id: str) -> Any:
39
46
  """Get a specific audit template by ID."""
40
47
  cited_ctx = _get_ctx(ctx)
@@ -48,7 +55,10 @@ async def get_audit_template(ctx: Context[Any, CitedContext, Any], named_audit_i
48
55
  return _api_error_response(e)
49
56
 
50
57
 
51
- @mcp.tool()
58
+ @mcp.tool(
59
+ title="Create Audit Template",
60
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False, idempotentHint=False, openWorldHint=False),
61
+ )
52
62
  async def create_audit_template(
53
63
  ctx: Context[Any, CitedContext, Any],
54
64
  name: str,
@@ -79,7 +89,10 @@ async def create_audit_template(
79
89
  return _api_error_response(e)
80
90
 
81
91
 
82
- @mcp.tool()
92
+ @mcp.tool(
93
+ title="Update Audit Template",
94
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False, idempotentHint=True, openWorldHint=False),
95
+ )
83
96
  async def update_audit_template(
84
97
  ctx: Context[Any, CitedContext, Any],
85
98
  named_audit_id: str,
@@ -114,7 +127,10 @@ async def update_audit_template(
114
127
  return _api_error_response(e)
115
128
 
116
129
 
117
- @mcp.tool()
130
+ @mcp.tool(
131
+ title="Delete Audit Template",
132
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=True, idempotentHint=True, openWorldHint=False),
133
+ )
118
134
  async def delete_audit_template(
119
135
  ctx: Context[Any, CitedContext, Any], named_audit_id: str
120
136
  ) -> Any:
@@ -136,7 +152,10 @@ async def delete_audit_template(
136
152
  return _api_error_response(e)
137
153
 
138
154
 
139
- @mcp.tool()
155
+ @mcp.tool(
156
+ title="Start Audit",
157
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False, idempotentHint=False, openWorldHint=False),
158
+ )
140
159
  async def start_audit(
141
160
  ctx: Context[Any, CitedContext, Any],
142
161
  named_audit_id: str,
@@ -165,7 +184,10 @@ async def start_audit(
165
184
  return _api_error_response(e)
166
185
 
167
186
 
168
- @mcp.tool()
187
+ @mcp.tool(
188
+ title="Get Audit Status",
189
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
190
+ )
169
191
  async def get_audit_status(ctx: Context[Any, CitedContext, Any], job_id: str) -> Any:
170
192
  """Check the status of a running audit job."""
171
193
  cited_ctx = _get_ctx(ctx)
@@ -177,7 +199,10 @@ async def get_audit_status(ctx: Context[Any, CitedContext, Any], job_id: str) ->
177
199
  return _api_error_response(e)
178
200
 
179
201
 
180
- @mcp.tool()
202
+ @mcp.tool(
203
+ title="Get Audit Results",
204
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
205
+ )
181
206
  async def get_audit_result(ctx: Context[Any, CitedContext, Any], job_id: str) -> Any:
182
207
  """Get the results of a completed audit job."""
183
208
  cited_ctx = _get_ctx(ctx)
@@ -189,7 +214,10 @@ async def get_audit_result(ctx: Context[Any, CitedContext, Any], job_id: str) ->
189
214
  return _api_error_response(e)
190
215
 
191
216
 
192
- @mcp.tool()
217
+ @mcp.tool(
218
+ title="List Audits",
219
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
220
+ )
193
221
  async def list_audits(
194
222
  ctx: Context[Any, CitedContext, Any],
195
223
  business_id: str | None = None,
@@ -5,6 +5,7 @@ from typing import Any
5
5
 
6
6
  import anyio
7
7
  from mcp.server.fastmcp import Context
8
+ from mcp.types import ToolAnnotations
8
9
 
9
10
  from cited_core.api import endpoints
10
11
  from cited_core.auth.oauth_server import OAuthCallbackServer
@@ -16,7 +17,10 @@ from cited_mcp.server import mcp
16
17
  from cited_mcp.tools._helpers import _api_error_response, _auth_check, _get_ctx
17
18
 
18
19
 
19
- @mcp.tool()
20
+ @mcp.tool(
21
+ title="Check Auth Status",
22
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
23
+ )
20
24
  async def check_auth_status(ctx: Context[Any, CitedContext, Any]) -> Any:
21
25
  """Check if the user is authenticated and return their account info.
22
26
 
@@ -48,7 +52,10 @@ def _clear_session(cited_ctx: CitedContext, env: str) -> None:
48
52
  cited_ctx.client._client.cookies.delete("advgeo_session")
49
53
 
50
54
 
51
- @mcp.tool()
55
+ @mcp.tool(
56
+ title="Log In",
57
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False, idempotentHint=False, openWorldHint=False),
58
+ )
52
59
  async def login(
53
60
  ctx: Context[Any, CitedContext, Any],
54
61
  env: str | None = None,
@@ -101,14 +108,28 @@ async def login(
101
108
  return {"success": True, "message": f"Logged in successfully (env: {target_env})"}
102
109
 
103
110
 
104
- @mcp.tool()
111
+ @mcp.tool(
112
+ title="Log Out",
113
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False, idempotentHint=True, openWorldHint=False),
114
+ )
105
115
  async def logout(ctx: Context[Any, CitedContext, Any]) -> Any:
106
116
  """Log out of Cited by clearing the stored authentication token.
107
117
 
108
- Use this when you need to switch accounts or if the current session
109
- is invalid. After logging out, use the 'login' tool to authenticate again.
118
+ In remote mode (HTTP transport), authentication is managed by the connector —
119
+ disconnect and reconnect to switch accounts. This tool is for stdio transport.
110
120
  """
111
- cited_ctx = _get_ctx(ctx)
112
- env = cited_ctx.env
113
- _clear_session(cited_ctx, env)
121
+ lc: CitedContext = ctx.request_context.lifespan_context
122
+
123
+ # Remote mode: lifespan client has no token; auth is via OAuth connector
124
+ if not lc.client.token:
125
+ return {
126
+ "success": False,
127
+ "message": (
128
+ "Authentication is managed by your Claude connector. "
129
+ "To switch accounts, disconnect and reconnect the Cited connector."
130
+ ),
131
+ }
132
+
133
+ env = lc.env
134
+ _clear_session(lc, env)
114
135
  return {"success": True, "message": f"Logged out successfully (env: {env})"}
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import Any
4
4
 
5
5
  from mcp.server.fastmcp import Context
6
+ from mcp.types import ToolAnnotations
6
7
 
7
8
  from cited_core.api import endpoints
8
9
  from cited_core.errors import CitedAPIError
@@ -11,7 +12,10 @@ from cited_mcp.server import mcp
11
12
  from cited_mcp.tools._helpers import _api_error_response, _auth_check, _get_ctx
12
13
 
13
14
 
14
- @mcp.tool()
15
+ @mcp.tool(
16
+ title="List Businesses",
17
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
18
+ )
15
19
  async def list_businesses(ctx: Context[Any, CitedContext, Any]) -> Any:
16
20
  """List all businesses for the authenticated user."""
17
21
  cited_ctx = _get_ctx(ctx)
@@ -23,7 +27,10 @@ async def list_businesses(ctx: Context[Any, CitedContext, Any]) -> Any:
23
27
  return _api_error_response(e)
24
28
 
25
29
 
26
- @mcp.tool()
30
+ @mcp.tool(
31
+ title="Get Business Details",
32
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
33
+ )
27
34
  async def get_business(ctx: Context[Any, CitedContext, Any], business_id: str) -> Any:
28
35
  """Get details for a specific business by ID."""
29
36
  cited_ctx = _get_ctx(ctx)
@@ -35,7 +42,10 @@ async def get_business(ctx: Context[Any, CitedContext, Any], business_id: str) -
35
42
  return _api_error_response(e)
36
43
 
37
44
 
38
- @mcp.tool()
45
+ @mcp.tool(
46
+ title="Create Business",
47
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False, idempotentHint=False, openWorldHint=False),
48
+ )
39
49
  async def create_business(
40
50
  ctx: Context[Any, CitedContext, Any],
41
51
  name: str,
@@ -77,7 +87,10 @@ async def create_business(
77
87
  return _api_error_response(e)
78
88
 
79
89
 
80
- @mcp.tool()
90
+ @mcp.tool(
91
+ title="Update Business",
92
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False, idempotentHint=True, openWorldHint=False),
93
+ )
81
94
  async def update_business(
82
95
  ctx: Context[Any, CitedContext, Any],
83
96
  business_id: str,
@@ -116,7 +129,10 @@ async def update_business(
116
129
  return _api_error_response(e)
117
130
 
118
131
 
119
- @mcp.tool()
132
+ @mcp.tool(
133
+ title="Delete Business",
134
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=True, idempotentHint=True, openWorldHint=False),
135
+ )
120
136
  async def delete_business(ctx: Context[Any, CitedContext, Any], business_id: str) -> Any:
121
137
  """Delete a business and all its associated data.
122
138
 
@@ -138,7 +154,10 @@ async def delete_business(ctx: Context[Any, CitedContext, Any], business_id: str
138
154
  return _api_error_response(e)
139
155
 
140
156
 
141
- @mcp.tool()
157
+ @mcp.tool(
158
+ title="Crawl Business Website",
159
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False, idempotentHint=False, openWorldHint=True),
160
+ )
142
161
  async def crawl_business(ctx: Context[Any, CitedContext, Any], business_id: str) -> Any:
143
162
  """Start a crawl job for a business. Returns a job_id you can poll with get_job_status."""
144
163
  cited_ctx = _get_ctx(ctx)
@@ -150,7 +169,10 @@ async def crawl_business(ctx: Context[Any, CitedContext, Any], business_id: str)
150
169
  return _api_error_response(e)
151
170
 
152
171
 
153
- @mcp.tool()
172
+ @mcp.tool(
173
+ title="Get Health Scores",
174
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
175
+ )
154
176
  async def get_health_scores(ctx: Context[Any, CitedContext, Any], business_id: str) -> Any:
155
177
  """Get GEO health scores for a business."""
156
178
  cited_ctx = _get_ctx(ctx)
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import Any
4
4
 
5
5
  from mcp.server.fastmcp import Context
6
+ from mcp.types import ToolAnnotations
6
7
 
7
8
  from cited_core.api import endpoints
8
9
  from cited_core.errors import CitedAPIError
@@ -17,7 +18,10 @@ _STATUS_ENDPOINTS = {
17
18
  }
18
19
 
19
20
 
20
- @mcp.tool()
21
+ @mcp.tool(
22
+ title="Get Job Status",
23
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
24
+ )
21
25
  async def get_job_status(
22
26
  ctx: Context[Any, CitedContext, Any],
23
27
  job_id: str,
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import Any
4
4
 
5
5
  from mcp.server.fastmcp import Context
6
+ from mcp.types import ToolAnnotations
6
7
 
7
8
  from cited_core.api import endpoints
8
9
  from cited_core.errors import CitedAPIError
@@ -11,7 +12,10 @@ from cited_mcp.server import mcp
11
12
  from cited_mcp.tools._helpers import _api_error_response, _auth_check, _get_ctx
12
13
 
13
14
 
14
- @mcp.tool()
15
+ @mcp.tool(
16
+ title="Start Recommendations",
17
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False, idempotentHint=False, openWorldHint=False),
18
+ )
15
19
  async def start_recommendation(ctx: Context[Any, CitedContext, Any], audit_job_id: str) -> Any:
16
20
  """Start a recommendation job based on a completed audit.
17
21
 
@@ -31,7 +35,10 @@ async def start_recommendation(ctx: Context[Any, CitedContext, Any], audit_job_i
31
35
  return _api_error_response(e)
32
36
 
33
37
 
34
- @mcp.tool()
38
+ @mcp.tool(
39
+ title="Get Recommendation Status",
40
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
41
+ )
35
42
  async def get_recommendation_status(ctx: Context[Any, CitedContext, Any], job_id: str) -> Any:
36
43
  """Check the status of a recommendation job."""
37
44
  cited_ctx = _get_ctx(ctx)
@@ -43,7 +50,10 @@ async def get_recommendation_status(ctx: Context[Any, CitedContext, Any], job_id
43
50
  return _api_error_response(e)
44
51
 
45
52
 
46
- @mcp.tool()
53
+ @mcp.tool(
54
+ title="Get Recommendation Results",
55
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
56
+ )
47
57
  async def get_recommendation_result(ctx: Context[Any, CitedContext, Any], job_id: str) -> Any:
48
58
  """Get the full results of a completed recommendation job."""
49
59
  cited_ctx = _get_ctx(ctx)
@@ -55,7 +65,10 @@ async def get_recommendation_result(ctx: Context[Any, CitedContext, Any], job_id
55
65
  return _api_error_response(e)
56
66
 
57
67
 
58
- @mcp.tool()
68
+ @mcp.tool(
69
+ title="Get Recommendation Insights",
70
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
71
+ )
59
72
  async def get_recommendation_insights(ctx: Context[Any, CitedContext, Any], job_id: str) -> Any:
60
73
  """Get actionable insights from a recommendation, with source_type and source_id for solutions.
61
74
 
@@ -96,7 +109,10 @@ async def get_recommendation_insights(ctx: Context[Any, CitedContext, Any], job_
96
109
  return insights
97
110
 
98
111
 
99
- @mcp.tool()
112
+ @mcp.tool(
113
+ title="List Recommendations",
114
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
115
+ )
100
116
  async def list_recommendations(
101
117
  ctx: Context[Any, CitedContext, Any], audit_job_id: str
102
118
  ) -> Any:
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import Any
4
4
 
5
5
  from mcp.server.fastmcp import Context
6
+ from mcp.types import ToolAnnotations
6
7
 
7
8
  from cited_core.api import endpoints
8
9
  from cited_core.errors import CitedAPIError
@@ -11,7 +12,10 @@ from cited_mcp.server import mcp
11
12
  from cited_mcp.tools._helpers import _api_error_response, _auth_check, _get_ctx
12
13
 
13
14
 
14
- @mcp.tool()
15
+ @mcp.tool(
16
+ title="Start Solution",
17
+ annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False, idempotentHint=False, openWorldHint=False),
18
+ )
15
19
  async def start_solution(
16
20
  ctx: Context[Any, CitedContext, Any],
17
21
  recommendation_job_id: str,
@@ -42,7 +46,10 @@ async def start_solution(
42
46
  return _api_error_response(e)
43
47
 
44
48
 
45
- @mcp.tool()
49
+ @mcp.tool(
50
+ title="Get Solution Status",
51
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
52
+ )
46
53
  async def get_solution_status(ctx: Context[Any, CitedContext, Any], job_id: str) -> Any:
47
54
  """Check the status of a solution generation job."""
48
55
  cited_ctx = _get_ctx(ctx)
@@ -54,7 +61,10 @@ async def get_solution_status(ctx: Context[Any, CitedContext, Any], job_id: str)
54
61
  return _api_error_response(e)
55
62
 
56
63
 
57
- @mcp.tool()
64
+ @mcp.tool(
65
+ title="Get Solution Results",
66
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
67
+ )
58
68
  async def get_solution_result(ctx: Context[Any, CitedContext, Any], job_id: str) -> Any:
59
69
  """Get the results of a completed solution generation job."""
60
70
  cited_ctx = _get_ctx(ctx)
@@ -66,7 +76,10 @@ async def get_solution_result(ctx: Context[Any, CitedContext, Any], job_id: str)
66
76
  return _api_error_response(e)
67
77
 
68
78
 
69
- @mcp.tool()
79
+ @mcp.tool(
80
+ title="List Solutions",
81
+ annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False),
82
+ )
70
83
  async def list_solutions(
71
84
  ctx: Context[Any, CitedContext, Any],
72
85
  business_id: str | None = None,
@@ -4,14 +4,14 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cited-cli"
7
- version = "0.3.3"
7
+ version = "0.3.4"
8
8
  description = "CLI for the Cited GEO platform"
9
9
  readme = "README.md"
10
10
  license = "LicenseRef-Proprietary"
11
11
  requires-python = ">=3.11"
12
12
  authors = [{ name = "Cited", email = "support@youcited.com" }]
13
13
  dependencies = [
14
- "cited-core>=0.3.3",
14
+ "cited-core>=0.3.4",
15
15
  "typer>=0.15.0",
16
16
  "rich>=13.0.0",
17
17
  ]
@@ -20,13 +20,13 @@ dependencies = [
20
20
  cited = "cited_cli.app:main"
21
21
 
22
22
  [project.optional-dependencies]
23
- mcp = ["cited-mcp>=0.3.3"]
23
+ mcp = ["cited-mcp>=0.3.4"]
24
24
  dev = [
25
25
  "pytest>=8.0",
26
26
  "respx>=0.21",
27
27
  "ruff>=0.4",
28
28
  "mypy>=1.10",
29
- "cited-mcp>=0.3.3",
29
+ "cited-mcp>=0.3.4",
30
30
  ]
31
31
 
32
32
  [tool.hatch.build.targets.wheel]