sourcecode 1.35.6__tar.gz → 1.35.7__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 (103) hide show
  1. {sourcecode-1.35.6 → sourcecode-1.35.7}/PKG-INFO +1 -1
  2. {sourcecode-1.35.6 → sourcecode-1.35.7}/pyproject.toml +1 -1
  3. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/__init__.py +1 -1
  4. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/mcp/registry.py +178 -6
  5. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/mcp/server.py +23 -4
  6. {sourcecode-1.35.6 → sourcecode-1.35.7}/.github/workflows/build-windows.yml +0 -0
  7. {sourcecode-1.35.6 → sourcecode-1.35.7}/.gitignore +0 -0
  8. {sourcecode-1.35.6 → sourcecode-1.35.7}/.ruff.toml +0 -0
  9. {sourcecode-1.35.6 → sourcecode-1.35.7}/CHANGELOG.md +0 -0
  10. {sourcecode-1.35.6 → sourcecode-1.35.7}/CONTRIBUTING.md +0 -0
  11. {sourcecode-1.35.6 → sourcecode-1.35.7}/LICENSE +0 -0
  12. {sourcecode-1.35.6 → sourcecode-1.35.7}/README.md +0 -0
  13. {sourcecode-1.35.6 → sourcecode-1.35.7}/SECURITY.md +0 -0
  14. {sourcecode-1.35.6 → sourcecode-1.35.7}/raw +0 -0
  15. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/adaptive_scanner.py +0 -0
  16. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/architecture_analyzer.py +0 -0
  17. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/architecture_summary.py +0 -0
  18. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/ast_extractor.py +0 -0
  19. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/cache.py +0 -0
  20. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/canonical_ir.py +0 -0
  21. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/cir_graphs.py +0 -0
  22. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/classifier.py +0 -0
  23. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/cli.py +0 -0
  24. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/code_notes_analyzer.py +0 -0
  25. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/confidence_analyzer.py +0 -0
  26. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/context_scorer.py +0 -0
  27. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/context_summarizer.py +0 -0
  28. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/contract_model.py +0 -0
  29. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/contract_pipeline.py +0 -0
  30. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/coverage_parser.py +0 -0
  31. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/dependency_analyzer.py +0 -0
  32. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/__init__.py +0 -0
  33. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/base.py +0 -0
  34. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/csproj_parser.py +0 -0
  35. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/dart.py +0 -0
  36. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/dotnet.py +0 -0
  37. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/elixir.py +0 -0
  38. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/go.py +0 -0
  39. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/heuristic.py +0 -0
  40. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/hybrid.py +0 -0
  41. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/java.py +0 -0
  42. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/jvm_ext.py +0 -0
  43. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/nodejs.py +0 -0
  44. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/parsers.py +0 -0
  45. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/php.py +0 -0
  46. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/project.py +0 -0
  47. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/python.py +0 -0
  48. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/ruby.py +0 -0
  49. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/rust.py +0 -0
  50. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/systems.py +0 -0
  51. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/terraform.py +0 -0
  52. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/detectors/tooling.py +0 -0
  53. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/doc_analyzer.py +0 -0
  54. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/entrypoint_classifier.py +0 -0
  55. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/env_analyzer.py +0 -0
  56. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/error_schema.py +0 -0
  57. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/file_classifier.py +0 -0
  58. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/flow_analyzer.py +0 -0
  59. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/git_analyzer.py +0 -0
  60. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/graph_analyzer.py +0 -0
  61. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/license.py +0 -0
  62. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/mcp/__init__.py +0 -0
  63. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  64. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  65. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  66. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  67. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  68. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/mcp/orchestrator.py +0 -0
  69. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/mcp/runner.py +0 -0
  70. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/mcp_nudge.py +0 -0
  71. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/metrics_analyzer.py +0 -0
  72. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/output_budget.py +0 -0
  73. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/path_filters.py +0 -0
  74. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/pr_comment_renderer.py +0 -0
  75. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/prepare_context.py +0 -0
  76. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/progress.py +0 -0
  77. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/ranking_engine.py +0 -0
  78. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/redactor.py +0 -0
  79. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/relevance_scorer.py +0 -0
  80. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/repo_classifier.py +0 -0
  81. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/repository_ir.py +0 -0
  82. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/ris.py +0 -0
  83. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/runtime_classifier.py +0 -0
  84. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/scanner.py +0 -0
  85. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/schema.py +0 -0
  86. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/semantic_analyzer.py +0 -0
  87. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/serializer.py +0 -0
  88. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/spring_event_topology.py +0 -0
  89. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/spring_findings.py +0 -0
  90. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/spring_impact.py +0 -0
  91. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/spring_model.py +0 -0
  92. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/spring_security_audit.py +0 -0
  93. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/spring_semantic.py +0 -0
  94. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/spring_tx_analyzer.py +0 -0
  95. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/summarizer.py +0 -0
  96. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/telemetry/__init__.py +0 -0
  97. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/telemetry/config.py +0 -0
  98. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/telemetry/consent.py +0 -0
  99. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/telemetry/events.py +0 -0
  100. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/telemetry/filters.py +0 -0
  101. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/telemetry/transport.py +0 -0
  102. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/tree_utils.py +0 -0
  103. {sourcecode-1.35.6 → sourcecode-1.35.7}/src/sourcecode/workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.35.6
3
+ Version: 1.35.7
4
4
  Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
5
5
  License-File: LICENSE
6
6
  Keywords: agents,ai,codebase,context,developer-tools,llm
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "1.35.6"
7
+ version = "1.35.7"
8
8
  description = "Persistent structural context and ultra-fast repeated analysis for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Deterministic codebase context maps for AI coding agents."""
2
2
 
3
- __version__ = "1.35.6"
3
+ __version__ = "1.35.7"
@@ -10,7 +10,7 @@ Internal helpers remain explicitly marked and are not exported to MCP.
10
10
  """
11
11
  from __future__ import annotations
12
12
 
13
- from dataclasses import dataclass, field
13
+ from dataclasses import dataclass, field, replace
14
14
  import inspect
15
15
  from functools import lru_cache
16
16
  from typing import Any, Callable, Mapping
@@ -69,6 +69,7 @@ class ToolSpec:
69
69
  aliases: tuple[str, ...] = ()
70
70
  internal: bool = False
71
71
  not_exposed_to_cli: bool = False
72
+ mcp_hidden: bool = False
72
73
  docstring: str = ""
73
74
  runtime_command: str = ""
74
75
  _argv_builder: Callable[[Mapping[str, Any]], list[str]] | None = field(
@@ -82,6 +83,10 @@ class ToolSpec:
82
83
  def public(self) -> bool:
83
84
  return not self.internal and not self.not_exposed_to_cli
84
85
 
86
+ @property
87
+ def mcp_visible(self) -> bool:
88
+ return self.public and not self.mcp_hidden
89
+
85
90
  def build_argv(self, inputs: Mapping[str, Any]) -> list[str]:
86
91
  if self._argv_builder is None:
87
92
  raise RuntimeError(f"ToolSpec '{self.name}' has no argv builder")
@@ -488,8 +493,11 @@ def _alias_spec(
488
493
  aliases: tuple[str, ...] = (),
489
494
  internal: bool = False,
490
495
  not_exposed_to_cli: bool = False,
496
+ mcp_hidden: bool = False,
497
+ docstring_override: str | None = None,
491
498
  validator: Callable[[Mapping[str, Any]], str | None] | None = None,
492
499
  ) -> ToolSpec:
500
+ doc = docstring_override or _build_contract_doc(description, params, cli_path, supported_targets, unsupported_targets)
493
501
  return ToolSpec(
494
502
  name=name,
495
503
  description=description,
@@ -500,7 +508,8 @@ def _alias_spec(
500
508
  aliases=aliases,
501
509
  internal=internal,
502
510
  not_exposed_to_cli=not_exposed_to_cli,
503
- docstring=_build_contract_doc(description, params, cli_path, supported_targets, unsupported_targets),
511
+ mcp_hidden=mcp_hidden,
512
+ docstring=doc,
504
513
  runtime_command=" ".join(cli_path) if cli_path else "sourcecode",
505
514
  _argv_builder=argv_builder,
506
515
  validator=validator,
@@ -788,17 +797,169 @@ def _internal_specs() -> list[ToolSpec]:
788
797
  ]
789
798
 
790
799
 
800
+ # Canonical CLI tools that are MCP-noise: raw passthroughs, meta-commands, and duplicates
801
+ # superseded by cleaner alias variants. Still tracked by validate_registry(); just not served.
802
+ _MCP_HIDDEN_CANONICAL_TOOLS: frozenset[str] = frozenset({
803
+ # Raw CLI passthroughs (clean alias exists)
804
+ "sourcecode_root", # 40+ flags, no agent guidance; use get_compact_context / get_agent_context
805
+ "prepare_context", # requires knowing subtask string; use task-specific aliases
806
+ "repo_ir", # raw IR dump; use get_ir_summary
807
+ "fix_bug", # raw Pro command; use fix_bug_context for MCP
808
+ "review_pr", # raw Pro command; use review_pr_context for MCP
809
+ "onboard", # raw with llm_prompt/copy flags; use onboard_context
810
+ # Duplicates (inferior params — cleaner alias exists)
811
+ "impact", # path/target order reversed vs get_impact_context; use get_impact_context
812
+ "cold_start", # duplicate of get_cold_start_context
813
+ "cache_freshness", # duplicate of check_freshness
814
+ "modernize", # duplicate of modernize_context
815
+ # Curated overrides — canonical CLI spec replaced by cleaner alias with same name.
816
+ # Listed here so validate_registry() skips CLI param-drift checks on the alias.
817
+ "spring_audit", # curated: repo_path + scope + min_severity only (strips output_path/format/copy)
818
+ "impact_chain", # curated: repo_path + symbol + depth + query_type with choices
819
+ # MCP self-management (an agent is not the MCP client admin)
820
+ "mcp_init",
821
+ "mcp_serve",
822
+ "mcp_status",
823
+ "mcp_remove",
824
+ "mcp_list_tools",
825
+ # Telemetry sub-commands (consolidated into telemetry(action=))
826
+ "telemetry_status",
827
+ "telemetry_enable",
828
+ "telemetry_disable",
829
+ })
830
+
831
+
832
+ def _java_spring_aliases() -> list[ToolSpec]:
833
+ """Curated MCP overrides for Java/Spring tools.
834
+
835
+ These replace the auto-generated canonical specs with cleaner param surfaces:
836
+ - repo_path (not raw `path`) for consistency with all other MCP tools
837
+ - MCP-irrelevant CLI flags (output_path, format, copy) stripped
838
+ - query_type choices documented so agents discover event topology
839
+ - Rich docstrings instead of contract-format stubs
840
+ """
841
+ validate_repo_path = _repo_path_validator()
842
+
843
+ _SPRING_AUDIT_DOC = """\
844
+ Spring semantic audit: TX anomalies + security surface. JAVA/SPRING ONLY.
845
+
846
+ Do NOT call on non-Java repositories — returns spring_detected=false with no findings.
847
+
848
+ Patterns detected:
849
+ TX-001: @Transactional missing rollbackFor for checked exceptions
850
+ TX-002: propagation=NEVER/NOT_SUPPORTED inside @Transactional scope
851
+ TX-003: readOnly=true method calling write operations
852
+ TX-004: REQUIRES_NEW nested inside REQUIRED (TX isolation breach risk)
853
+ TX-005: @Async method called within @Transactional context (TX context lost)
854
+ SEC-001: public endpoint with no security annotation (none_detected policy)
855
+ SEC-002: security annotation on non-endpoint method (misplaced)
856
+ SEC-003: missing auth on admin-pattern operations
857
+
858
+ Returns: schema_version, spring_detected, scope, summary, findings[], limitations, metadata.
859
+ findings fields: id, pattern_id, category, severity, confidence, title, symbol,
860
+ source_file, evidence, explanation, fix_hint.
861
+
862
+ repo_path: absolute path to the Java repository (default: current working directory).
863
+ scope: "all" (default) | "tx" (TX-001..005 only) | "security" (SEC-001..003 only)
864
+ min_severity: "low" (default) | "medium" | "high" | "critical"
865
+ """
866
+
867
+ _IMPACT_CHAIN_DOC = """\
868
+ Spring impact-chain: blast radius of a symbol with TX/SEC semantic enrichment. JAVA/SPRING ONLY.
869
+
870
+ Do NOT call on non-Java repositories — returns resolution=not_found.
871
+
872
+ Two query modes via query_type:
873
+ "impact" (default) — BFS call graph: direct_callers, indirect_callers, endpoints_affected,
874
+ transaction_boundary, security_surfaces, impact_findings (TX/SEC patterns in call chain).
875
+ "events" — event topology: publishers, consumers, propagation graph for an event class
876
+ or event publisher. Use when symbol is an event class (e.g. OrderPlacedEvent).
877
+
878
+ Returns: schema_version, symbol, resolution, direct_callers, indirect_callers,
879
+ endpoints_affected, transaction_boundary, security_surfaces, impact_findings,
880
+ analysis_warnings, risk_level, confidence, metadata.
881
+
882
+ symbol: FQN, class name, or Class#method.
883
+ Examples: "OrderService", "com.example.OrderService#placeOrder",
884
+ "OrderPlacedEvent" (with query_type="events" for event topology)
885
+ repo_path: absolute path to the Java repository (default: current working directory).
886
+ depth: BFS traversal depth 1–8 (default 4).
887
+ query_type: "impact" (default) | "events"
888
+ """
889
+
890
+ spring_audit = _alias_spec(
891
+ "spring_audit",
892
+ "Spring semantic audit: TX anomalies + security surface. JAVA/SPRING ONLY.",
893
+ ("spring-audit",),
894
+ (
895
+ ToolParamSpec("repo_path", "argument", str, required=False, default=".", is_path=True,
896
+ help="Absolute path to the Java repository."),
897
+ ToolParamSpec("scope", "option", str, required=False, default="all",
898
+ option_names=("--scope",), choices=("all", "tx", "security"),
899
+ help="all (default) | tx | security"),
900
+ ToolParamSpec("min_severity", "option", str, required=False, default="low",
901
+ option_names=("--min-severity",), choices=("low", "medium", "high", "critical"),
902
+ help="low (default) | medium | high | critical"),
903
+ ),
904
+ lambda inputs: [
905
+ "spring-audit",
906
+ str(inputs.get("repo_path", ".")),
907
+ "--scope", str(inputs.get("scope", "all")),
908
+ "--min-severity", str(inputs.get("min_severity", "low")),
909
+ ],
910
+ supported_targets=("repo_path",),
911
+ unsupported_targets=("file_path",),
912
+ validator=validate_repo_path,
913
+ docstring_override=_SPRING_AUDIT_DOC,
914
+ )
915
+
916
+ impact_chain = _alias_spec(
917
+ "impact_chain",
918
+ "Spring impact-chain: blast radius + TX/SEC enrichment. JAVA/SPRING ONLY.",
919
+ ("impact-chain",),
920
+ (
921
+ ToolParamSpec("symbol", "argument", str, required=True, default=None,
922
+ help="FQN, class name, or Class#method."),
923
+ ToolParamSpec("repo_path", "argument", str, required=False, default=".", is_path=True,
924
+ help="Absolute path to the Java repository."),
925
+ ToolParamSpec("depth", "option", int, required=False, default=4,
926
+ option_names=("--depth",), help="BFS depth 1–8 (default 4)."),
927
+ ToolParamSpec("query_type", "option", str, required=False, default="impact",
928
+ option_names=("--type",), choices=("impact", "events"),
929
+ help="impact (default) = call-chain blast radius; events = event topology"),
930
+ ),
931
+ lambda inputs: [
932
+ "impact-chain",
933
+ str(inputs["symbol"]),
934
+ str(inputs.get("repo_path", ".")),
935
+ "--depth", str(inputs.get("depth", 4)),
936
+ "--type", str(inputs.get("query_type", "impact")),
937
+ ],
938
+ supported_targets=("repo_path", "class_name"),
939
+ unsupported_targets=("file_path",),
940
+ validator=validate_repo_path,
941
+ docstring_override=_IMPACT_CHAIN_DOC,
942
+ )
943
+
944
+ return [spring_audit, impact_chain]
945
+
946
+
791
947
  @lru_cache(maxsize=1)
792
948
  def build_tool_specs() -> tuple[ToolSpec, ...]:
793
949
  """Build the full MCP registry from the live CLI runtime."""
794
- canonical = [
950
+ canonical_raw = [
795
951
  _canonical_spec_for_runtime_command(runtime)
796
952
  for runtime in discover_runtime_commands()
797
953
  if (runtime.callback is not None or runtime.path == ())
798
954
  and (not runtime.hidden or runtime.path == ("analyze",))
799
955
  ]
956
+ # Mark canonical tools that should not be served via MCP (validate_registry still checks them)
957
+ canonical = [
958
+ replace(spec, mcp_hidden=True) if spec.name in _MCP_HIDDEN_CANONICAL_TOOLS else spec
959
+ for spec in canonical_raw
960
+ ]
800
961
 
801
- aliases = _root_aliases() + _prepare_context_aliases()
962
+ aliases = _root_aliases() + _prepare_context_aliases() + _java_spring_aliases()
802
963
  internals = _internal_specs()
803
964
 
804
965
  merged: dict[str, ToolSpec] = {}
@@ -842,6 +1003,11 @@ def validate_registry() -> list[str]:
842
1003
  spec = registry_by_path.get(path)
843
1004
  if spec is None:
844
1005
  continue
1006
+ # Skip docstring/param drift for mcp_hidden tools and intentional curated overrides.
1007
+ # Curated aliases (e.g. spring_audit, impact_chain) replace canonical CLI specs with
1008
+ # cleaner MCP surfaces — their params diverge from the raw CLI by design.
1009
+ if spec.name in _MCP_HIDDEN_CANONICAL_TOOLS or spec.mcp_hidden:
1010
+ continue
845
1011
  expected_doc = _first_doc_line(runtime.docstring or runtime.help or "")
846
1012
  if expected_doc and expected_doc not in spec.description:
847
1013
  issues.append(f"docstring_mismatch:{spec.name}")
@@ -853,9 +1019,15 @@ def validate_registry() -> list[str]:
853
1019
  return issues
854
1020
 
855
1021
 
1022
+ @lru_cache(maxsize=1)
1023
+ def build_mcp_tool_specs() -> tuple[ToolSpec, ...]:
1024
+ """Tool specs actually served via MCP: public and not mcp_hidden."""
1025
+ return tuple(spec for spec in build_tool_specs() if spec.mcp_visible)
1026
+
1027
+
856
1028
  def mcp_tool_specs() -> tuple[ToolSpec, ...]:
857
- """Public tool specs only."""
858
- return build_public_tool_specs()
1029
+ """Tool specs served via MCP (public, not mcp_hidden)."""
1030
+ return build_mcp_tool_specs()
859
1031
 
860
1032
 
861
1033
  def mcp_internal_tool_specs() -> tuple[ToolSpec, ...]:
@@ -1179,17 +1179,36 @@ def telemetry(action: str) -> dict:
1179
1179
  return _execute(["telemetry", action])
1180
1180
 
1181
1181
 
1182
+ _NATIVE_MCP_TOOLS: frozenset[str] = frozenset({
1183
+ "start_session",
1184
+ "analyze_task",
1185
+ "run_pr_review_flow",
1186
+ "run_bug_investigation_flow",
1187
+ "run_feature_flow",
1188
+ })
1189
+
1190
+
1182
1191
  def _finalize_mcp_registry() -> None:
1183
- """Replace manual tool registration with the runtime-generated registry."""
1184
- from sourcecode.mcp.registry import build_public_tool_specs, make_tool_callable, validate_registry
1192
+ """Sync the MCP server with the runtime-generated registry.
1193
+
1194
+ Removes every tool except the 5 native orchestration tools (start_session,
1195
+ analyze_task, flow runners) which are registered via @mcp.tool() in this
1196
+ module and have no backing CLI command. All other tools are rebuilt from the
1197
+ runtime-derived registry (build_mcp_tool_specs).
1198
+ """
1199
+ from sourcecode.mcp.registry import build_mcp_tool_specs, make_tool_callable, validate_registry
1200
+
1201
+ mcp_specs = build_mcp_tool_specs()
1185
1202
 
1203
+ # Remove everything except the native orchestration tools
1186
1204
  try:
1187
1205
  for tool in list(mcp._tool_manager.list_tools()): # type: ignore[attr-defined]
1188
- mcp.remove_tool(tool.name)
1206
+ if tool.name not in _NATIVE_MCP_TOOLS:
1207
+ mcp.remove_tool(tool.name)
1189
1208
  except Exception:
1190
1209
  pass
1191
1210
 
1192
- for spec in build_public_tool_specs():
1211
+ for spec in mcp_specs:
1193
1212
  tool_fn = make_tool_callable(spec)
1194
1213
  tool_fn.__doc__ = spec.docstring
1195
1214
  globals()[spec.name] = tool_fn
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes