Rebased foss-sandbox with upstream main#4
Closed
jawad-khan wants to merge 6 commits into
Closed
Conversation
Removed ~170 lines of over-engineered configurability that had safe, fixed values in practice: - AUTH_TYPE=SSO explicit opt-in replaces heuristic env-var sniffing (cognito_http_env_ready / cognito_http_configuration_intended) - Dropped MCP_COGNITO_REDIRECT_URI — MCP_BASE_URL is always the public URL by definition (OAuth clients must reach it), so a separate redirect URI override is never needed - Hardcoded COGNITO_OIDC_FORWARD_PKCE=false, COGNITO_TOKEN_ENDPOINT_AUTH_METHOD=none, COGNITO_REQUIRE_CONSENT=true, COGNITO_RELAX_OAUTH_RESOURCE_MISMATCH=true — all were already the defaults and never changed - Inlined _plane_root_base() and _httpx_verify() one-use helpers - Restored _plane_bearer_for info log (id_token forwarding); dropped the warning (we only use Cognito SSO, never Plane OAuth, so absence of id_token is never an actionable signal) - Added targeted tests for _plane_bearer_for and id_token header preference Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR significantly expands the Plane MCP server’s self-hosting and query capabilities by adding an AWS Cognito-backed HTTP mode, introducing Redis/AWS Secrets Manager-backed token storage selection, and evolving multiple MCP tools to support workspace slug bootstrap + PQL-based filtering.
Changes:
- Add Cognito SSO HTTP transport (
AUTH_TYPE=SSO) and supporting environment validation / callback handling. - Introduce configurable OAuth token storage (in-memory, Redis, Redis+password, ElastiCache+Secrets Manager) with eager connectivity checks.
- Update and extend tool surface: workspace slug bootstrap (
list_workspaces), PQL reference tooling, and multiple tools updated to acceptworkspace_slugoverrides and/or return paginated envelopes.
Reviewed changes
Copilot reviewed 37 out of 38 changed files in this pull request and generated 26 comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_workspaces_tool.py |
Adds unit tests for _plane_auth_headers behavior (Bearer vs X-Api-Key). |
tests/test_cognito_http.py |
Adds tests for Cognito HTTP env validation and ID-token attachment behavior. |
tests/test_client_context.py |
Adds tests for workspace slug resolution + ID-token bearer selection logic. |
tests/test_aws_secrets.py |
Adds comprehensive tests for Secrets Manager caching + Redis token store selection paths. |
README.md |
Documents Cognito HTTP self-hosted mode and adds list_workspaces to tool list. |
pyproject.toml |
Updates dependencies (fastmcp/plane-sdk/etc) and modifies project version. |
plane_mcp/tools/workspaces.py |
Adds list_workspaces, header construction helper, and workspace_slug overrides for workspace tools. |
plane_mcp/tools/work_logs.py |
Adds optional workspace_slug override to work log tools. |
plane_mcp/tools/work_items.py |
Major refactor: PQL-enabled list tools, paginated envelope returns, new helper tools, broader workspace_slug override work. |
plane_mcp/tools/work_item_types.py |
Adds workspace-scoped type support and optional workspace_slug. |
plane_mcp/tools/work_item_relations.py |
Adds optional workspace_slug and improves relation_type documentation formatting. |
plane_mcp/tools/work_item_properties.py |
Expands property tooling (workspace/project/type scope), adds options/value APIs, and optional workspace_slug in some entry points. |
plane_mcp/tools/work_item_links.py |
Adds optional workspace_slug override to link tools. |
plane_mcp/tools/work_item_comments.py |
Adds optional workspace_slug override to comment tools. |
plane_mcp/tools/work_item_activities.py |
Adds optional workspace_slug override to activity tools. |
plane_mcp/tools/users.py |
Adds optional workspace_slug override and clarifies slug requirements in docstring. |
plane_mcp/tools/states.py |
Adds optional workspace_slug override to state tools. |
plane_mcp/tools/projects.py |
Adds optional workspace_slug overrides broadly; introduces project archive/unarchive and estimate management tools. |
plane_mcp/tools/pql.py |
Adds on-demand get_pql_reference tool to reduce tool manifest size. |
plane_mcp/tools/pql_reference.py |
Adds brief/full PQL reference strings and hint text for tool schemas. |
plane_mcp/tools/pages.py |
Adds workspace/project page listing and work-item page link tools; partial workspace_slug override coverage. |
plane_mcp/tools/modules.py |
Adds optional workspace_slug, PQL-enabled module work item listing, and renames issue_ids → work_item_ids at tool level. |
plane_mcp/tools/milestones.py |
Adds optional workspace_slug overrides and renames issue_ids → work_item_ids at tool level. |
plane_mcp/tools/labels.py |
Adds optional workspace_slug override to label tools. |
plane_mcp/tools/intake.py |
Adds optional workspace_slug overrides and expands intake update semantics (status/snooze/duplicate). |
plane_mcp/tools/initiatives.py |
Adds optional workspace_slug override to initiative tools. |
plane_mcp/tools/epics.py |
Adds optional workspace_slug override to epic tools. |
plane_mcp/tools/cycles.py |
Adds optional workspace_slug, PQL-enabled cycle work item listing, and new archive/complete behaviors. |
plane_mcp/tools/__init__.py |
Registers the new PQL tool module. |
plane_mcp/storage.py |
Adds token store selection + Redis reachability checks + optional Secrets Manager auth. |
plane_mcp/server.py |
Switches OAuth transport token storage to build_token_store(). |
plane_mcp/cognito_http.py |
Adds Cognito SSO HTTP app, provider customization, env validation, and Starlette composition. |
plane_mcp/client.py |
Adds _plane_bearer_for and enforces non-empty workspace slug resolution with clear error. |
plane_mcp/aws_secrets.py |
Adds Secrets Manager helper with TTL cache + redis CredentialProvider integration. |
plane_mcp/auth/plane_oauth_provider.py |
Tweaks Plane internal base URL resolution logic. |
plane_mcp/__main__.py |
Adds AUTH_TYPE=SSO branch for Cognito HTTP mode and supports MCP_PATH_PREFIX mount prefixing. |
.env.test |
Documents Redis/token storage and prefix env vars for local/self-hosted setups. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
1
to
4
| [project] | ||
| name = "plane-mcp-server" | ||
| version = "0.2.10" | ||
| version = "0.2.9" | ||
| description = "A Model Context Protocol server for Plane integration" |
Comment on lines
+97
to
+101
| # REDIS_SSL defaults False here: plain Redis is the common case for | ||
| # static-password deployments. Set REDIS_SSL=true for TLS-fronted Redis. | ||
| use_ssl = _redis_ssl_enabled(default=False) | ||
| _ping_redis(redis_host, int(redis_port), password=password, ssl=use_ssl) | ||
| store = RedisStore(host=redis_host, port=int(redis_port), password=password) |
Comment on lines
+193
to
+205
| def _oauth_client_storage() -> MemoryStore | RedisStore: | ||
| global _oauth_kv_singleton | ||
| if _oauth_kv_singleton is not None: | ||
| return _oauth_kv_singleton | ||
| redis_host = os.getenv("REDIS_HOST", "").strip() | ||
| redis_port = os.getenv("REDIS_PORT", "").strip() | ||
| if redis_host and redis_port: | ||
| logger.info("Cognito HTTP: using Redis for OAuth storage") | ||
| _oauth_kv_singleton = RedisStore(host=redis_host, port=int(redis_port)) | ||
| else: | ||
| logger.warning("Cognito HTTP: in-memory OAuth storage (set REDIS_HOST/REDIS_PORT for production)") | ||
| _oauth_kv_singleton = MemoryStore() | ||
| return _oauth_kv_singleton |
Comment on lines
+112
to
+121
| def list_workspace_work_items( | ||
| pql: Annotated[str | None, Field(description=PQL_FIELD_HINT)] = None, | ||
| order_by: str | None = None, | ||
| per_page: int | None = None, | ||
| cursor: str | None = None, | ||
| expand: str | None = None, | ||
| fields: str | None = None, | ||
| external_id: str | None = None, | ||
| external_source: str | None = None, | ||
| ) -> dict[str, Any]: |
| next_cursor: Cursor for the next page. | ||
| prev_cursor: Cursor for the previous page. | ||
| """ | ||
| client, workspace_slug = get_plane_client_context() |
Comment on lines
+99
to
+119
| @mcp.tool() | ||
| def detach_page_from_work_item( | ||
| project_id: str, | ||
| work_item_id: str, | ||
| work_item_page_id: str, | ||
| ) -> None: | ||
| """ | ||
| Remove a page link from a work item. | ||
|
|
||
| Args: | ||
| project_id: UUID of the project | ||
| work_item_id: UUID of the work item | ||
| work_item_page_id: UUID of the work item page link (not the page ID) | ||
| """ | ||
| client, workspace_slug = get_plane_client_context() | ||
| client.work_items.pages.delete( | ||
| workspace_slug=workspace_slug, | ||
| project_id=project_id, | ||
| work_item_id=work_item_id, | ||
| work_item_page_id=work_item_page_id, | ||
| ) |
| return client.estimates.retrieve(workspace_slug=workspace_slug, project_id=project_id) | ||
|
|
||
| @mcp.tool() | ||
| def list_project_estimate_points(project_id: str, estimate_id: str) -> list[EstimatePoint]: |
| Returns: | ||
| List of EstimatePoint objects, each with id and value fields | ||
| """ | ||
| client, workspace_slug = get_plane_client_context() |
Comment on lines
+444
to
+452
| def create_project_estimate( | ||
| project_id: str, | ||
| name: str, | ||
| type: str | None = None, | ||
| description: str | None = None, | ||
| last_used: bool = True, | ||
| external_id: str | None = None, | ||
| external_source: str | None = None, | ||
| ) -> Estimate: |
| Returns: | ||
| Created Estimate object | ||
| """ | ||
| client, workspace_slug = get_plane_client_context() |
6dc1c17 to
838c572
Compare
Collaborator
|
Closing in favor of #5 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation / Background
Rebased foss-sandbox with upstream main.
Detail
Rebased foss-sandbox with upstream main.
Additional information
TIP: Provide additional information such as screenshots, benchmarks, reference to other repositories or alternative solutions
Checklist
Before submitting the PR make sure the following are checked:
[Fix #issue-number]