@tyroneross/build-loop 0.30.3
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.
- package/.agents/plugins/marketplace.json +10 -0
- package/.claude-plugin/marketplace.json +38 -0
- package/.claude-plugin/plugin.json +30 -0
- package/.codex-plugin/plugin.json +41 -0
- package/.cursor/rules/build-loop-surface.mdc +22 -0
- package/AGENTS.md +498 -0
- package/LICENSE +202 -0
- package/README.md +403 -0
- package/agents/alignment-checker.md +124 -0
- package/agents/api-assessor.md +136 -0
- package/agents/architecture-scout.md +185 -0
- package/agents/assessment-orchestrator.md +163 -0
- package/agents/build-orchestrator.md +198 -0
- package/agents/database-assessor.md +133 -0
- package/agents/design-contract-specialist.md +239 -0
- package/agents/fact-checker.md +69 -0
- package/agents/fix-critique.md +161 -0
- package/agents/frontend-assessor.md +136 -0
- package/agents/implementer.md +185 -0
- package/agents/independent-auditor.md +143 -0
- package/agents/mock-scanner.md +78 -0
- package/agents/optimize-runner.md +112 -0
- package/agents/overfitting-reviewer.md +96 -0
- package/agents/performance-assessor.md +159 -0
- package/agents/plan-critic.md +85 -0
- package/agents/promotion-reviewer.md +121 -0
- package/agents/recurring-pattern-detector.md +248 -0
- package/agents/retrospective-synthesizer.md +109 -0
- package/agents/root-cause-investigator.md +285 -0
- package/agents/scope-auditor.md +121 -0
- package/agents/security-reviewer.md +151 -0
- package/agents/self-improvement-architect.md +125 -0
- package/agents/synthesis-critic.md +99 -0
- package/agents/transcript-pattern-miner.md +165 -0
- package/agents/ui-validator.md +193 -0
- package/codex-skills/build-loop/SKILL.md +20 -0
- package/codex-skills/debug-loop/SKILL.md +18 -0
- package/codex-skills/handoff/SKILL.md +22 -0
- package/codex-skills/knowledge/SKILL.md +21 -0
- package/codex-skills/optimize/SKILL.md +18 -0
- package/codex-skills/research/SKILL.md +18 -0
- package/commands/agent-rally-point.md +301 -0
- package/commands/assess.md +41 -0
- package/commands/debug.md +20 -0
- package/commands/debugger-detail.md +34 -0
- package/commands/debugger-scan.md +15 -0
- package/commands/debugger-status.md +20 -0
- package/commands/debugger.md +32 -0
- package/commands/handoff.md +113 -0
- package/commands/knowledge-review.md +16 -0
- package/commands/optimize.md +31 -0
- package/commands/plan-verify.md +39 -0
- package/commands/promote-experiment.md +129 -0
- package/commands/research.md +22 -0
- package/commands/run.md +12 -0
- package/commands/self-review.md +51 -0
- package/commands/start-prd.md +57 -0
- package/commands/test.md +34 -0
- package/dist/src/assessment-orchestrator.d.ts +78 -0
- package/dist/src/assessment-orchestrator.d.ts.map +1 -0
- package/dist/src/assessment-orchestrator.js +304 -0
- package/dist/src/assessment-orchestrator.js.map +1 -0
- package/dist/src/audit-miner.d.ts +21 -0
- package/dist/src/audit-miner.d.ts.map +1 -0
- package/dist/src/audit-miner.js +421 -0
- package/dist/src/audit-miner.js.map +1 -0
- package/dist/src/batch-operations.d.ts +30 -0
- package/dist/src/batch-operations.d.ts.map +1 -0
- package/dist/src/batch-operations.js +339 -0
- package/dist/src/batch-operations.js.map +1 -0
- package/dist/src/config.d.ts +83 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +176 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/context-engine.d.ts +45 -0
- package/dist/src/context-engine.d.ts.map +1 -0
- package/dist/src/context-engine.js +135 -0
- package/dist/src/context-engine.js.map +1 -0
- package/dist/src/debug-wrapper.d.ts +58 -0
- package/dist/src/debug-wrapper.d.ts.map +1 -0
- package/dist/src/debug-wrapper.js +285 -0
- package/dist/src/debug-wrapper.js.map +1 -0
- package/dist/src/index.d.ts +31 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +149 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/interactive-verifier.d.ts +26 -0
- package/dist/src/interactive-verifier.d.ts.map +1 -0
- package/dist/src/interactive-verifier.js +435 -0
- package/dist/src/interactive-verifier.js.map +1 -0
- package/dist/src/lessons.d.ts +59 -0
- package/dist/src/lessons.d.ts.map +1 -0
- package/dist/src/lessons.js +172 -0
- package/dist/src/lessons.js.map +1 -0
- package/dist/src/log-reader.d.ts +39 -0
- package/dist/src/log-reader.d.ts.map +1 -0
- package/dist/src/log-reader.js +291 -0
- package/dist/src/log-reader.js.map +1 -0
- package/dist/src/logger.d.ts +59 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +328 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/parallel-retrieval.d.ts +52 -0
- package/dist/src/parallel-retrieval.d.ts.map +1 -0
- package/dist/src/parallel-retrieval.js +309 -0
- package/dist/src/parallel-retrieval.js.map +1 -0
- package/dist/src/pattern-extractor.d.ts +30 -0
- package/dist/src/pattern-extractor.d.ts.map +1 -0
- package/dist/src/pattern-extractor.js +386 -0
- package/dist/src/pattern-extractor.js.map +1 -0
- package/dist/src/result-aggregator.d.ts +44 -0
- package/dist/src/result-aggregator.d.ts.map +1 -0
- package/dist/src/result-aggregator.js +315 -0
- package/dist/src/result-aggregator.js.map +1 -0
- package/dist/src/retrieval.d.ts +139 -0
- package/dist/src/retrieval.d.ts.map +1 -0
- package/dist/src/retrieval.js +724 -0
- package/dist/src/retrieval.js.map +1 -0
- package/dist/src/setup/auto-setup.d.ts +15 -0
- package/dist/src/setup/auto-setup.d.ts.map +1 -0
- package/dist/src/setup/auto-setup.js +157 -0
- package/dist/src/setup/auto-setup.js.map +1 -0
- package/dist/src/setup/configure-hooks.d.ts +8 -0
- package/dist/src/setup/configure-hooks.d.ts.map +1 -0
- package/dist/src/setup/configure-hooks.js +16 -0
- package/dist/src/setup/configure-hooks.js.map +1 -0
- package/dist/src/setup/create-slash-commands.d.ts +8 -0
- package/dist/src/setup/create-slash-commands.d.ts.map +1 -0
- package/dist/src/setup/create-slash-commands.js +101 -0
- package/dist/src/setup/create-slash-commands.js.map +1 -0
- package/dist/src/setup/index.d.ts +8 -0
- package/dist/src/setup/index.d.ts.map +1 -0
- package/dist/src/setup/index.js +17 -0
- package/dist/src/setup/index.js.map +1 -0
- package/dist/src/setup/inject-claude-md.d.ts +10 -0
- package/dist/src/setup/inject-claude-md.d.ts.map +1 -0
- package/dist/src/setup/inject-claude-md.js +150 -0
- package/dist/src/setup/inject-claude-md.js.map +1 -0
- package/dist/src/setup/uninstall.d.ts +22 -0
- package/dist/src/setup/uninstall.d.ts.map +1 -0
- package/dist/src/setup/uninstall.js +235 -0
- package/dist/src/setup/uninstall.js.map +1 -0
- package/dist/src/storage.d.ts +192 -0
- package/dist/src/storage.d.ts.map +1 -0
- package/dist/src/storage.js +1037 -0
- package/dist/src/storage.js.map +1 -0
- package/dist/src/string-similarity.d.ts +8 -0
- package/dist/src/string-similarity.d.ts.map +1 -0
- package/dist/src/string-similarity.js +57 -0
- package/dist/src/string-similarity.js.map +1 -0
- package/dist/src/traces/adapters/browser.d.ts +69 -0
- package/dist/src/traces/adapters/browser.d.ts.map +1 -0
- package/dist/src/traces/adapters/browser.js +280 -0
- package/dist/src/traces/adapters/browser.js.map +1 -0
- package/dist/src/traces/adapters/index.d.ts +23 -0
- package/dist/src/traces/adapters/index.d.ts.map +1 -0
- package/dist/src/traces/adapters/index.js +67 -0
- package/dist/src/traces/adapters/index.js.map +1 -0
- package/dist/src/traces/adapters/langchain.d.ts +42 -0
- package/dist/src/traces/adapters/langchain.d.ts.map +1 -0
- package/dist/src/traces/adapters/langchain.js +151 -0
- package/dist/src/traces/adapters/langchain.js.map +1 -0
- package/dist/src/traces/adapters/opentelemetry.d.ts +46 -0
- package/dist/src/traces/adapters/opentelemetry.d.ts.map +1 -0
- package/dist/src/traces/adapters/opentelemetry.js +164 -0
- package/dist/src/traces/adapters/opentelemetry.js.map +1 -0
- package/dist/src/traces/adapters/sentry.d.ts +58 -0
- package/dist/src/traces/adapters/sentry.d.ts.map +1 -0
- package/dist/src/traces/adapters/sentry.js +212 -0
- package/dist/src/traces/adapters/sentry.js.map +1 -0
- package/dist/src/traces/index.d.ts +10 -0
- package/dist/src/traces/index.d.ts.map +1 -0
- package/dist/src/traces/index.js +45 -0
- package/dist/src/traces/index.js.map +1 -0
- package/dist/src/traces/storage.d.ts +78 -0
- package/dist/src/traces/storage.d.ts.map +1 -0
- package/dist/src/traces/storage.js +399 -0
- package/dist/src/traces/storage.js.map +1 -0
- package/dist/src/traces/summarizer.d.ts +83 -0
- package/dist/src/traces/summarizer.d.ts.map +1 -0
- package/dist/src/traces/summarizer.js +247 -0
- package/dist/src/traces/summarizer.js.map +1 -0
- package/dist/src/traces/types.d.ts +365 -0
- package/dist/src/traces/types.d.ts.map +1 -0
- package/dist/src/traces/types.js +14 -0
- package/dist/src/traces/types.js.map +1 -0
- package/dist/src/types.d.ts +495 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +27 -0
- package/dist/src/types.js.map +1 -0
- package/docs/agent-surface-policy.md +45 -0
- package/docs/memory-setup.md +226 -0
- package/hooks/_arch_scan_bg.py +88 -0
- package/hooks/_plugin_drift_check_bg.py +85 -0
- package/hooks/_session_start_lib.sh +42 -0
- package/hooks/git/pre-push +141 -0
- package/hooks/hooks.json +126 -0
- package/hooks/post-commit +30 -0
- package/hooks/pre-commit +29 -0
- package/hooks/pre-edit-apppulse.sh +6 -0
- package/hooks/pre-edit-architecture.sh +106 -0
- package/hooks/pre-edit-rally-point.sh +92 -0
- package/hooks/session-start-apppulse.sh +6 -0
- package/hooks/session-start-architecture.sh +10 -0
- package/hooks/session-start-git-hooks.sh +12 -0
- package/hooks/session-start-plugin-drift.sh +27 -0
- package/hooks/session-start-rally-point.sh +44 -0
- package/hooks/session-start-retrieval.sh +24 -0
- package/hooks/session-start-worktree-gc.sh +105 -0
- package/hooks/test_apppulse_hooks.sh +6 -0
- package/hooks/test_rally_point_hooks.sh +388 -0
- package/hooks/test_sec008_hooks.sh +66 -0
- package/package.json +111 -0
- package/scripts/README.md +301 -0
- package/scripts/_db_url.py +61 -0
- package/scripts/_paths.py +445 -0
- package/scripts/blm.py +162 -0
- package/scripts/blm_api.py +263 -0
- package/scripts/check_cache_sync.py +490 -0
- package/scripts/embed_backend.py +475 -0
- package/scripts/install_memory.py +556 -0
- package/scripts/lessons_index/__init__.py +77 -0
- package/scripts/lessons_index/__main__.py +135 -0
- package/scripts/lessons_index/ingest.py +288 -0
- package/scripts/lessons_index/query.py +285 -0
- package/scripts/lessons_index/schema.py +114 -0
- package/scripts/memory_context/__init__.py +610 -0
- package/scripts/memory_graph/__init__.py +393 -0
- package/scripts/project_resolver.py +172 -0
- package/scripts/prune_codex_plugin_cache.py +23 -0
- package/scripts/prune_plugin_cache.py +359 -0
- package/scripts/semantic_index/__init__.py +482 -0
- package/scripts/semantic_index/_bench_hybrid.py +175 -0
- package/scripts/semantic_index/backfill.py +263 -0
- package/scripts/semantic_index/hybrid.py +174 -0
- package/scripts/semantic_index/test_backfill.py +292 -0
- package/scripts/semantic_index/test_hybrid.py +541 -0
- package/scripts/sync_navgator_lessons.py +666 -0
- package/scripts/sync_plugin_cache.py +388 -0
- package/skills/agent-rally-point/SKILL.md +165 -0
- package/skills/agent-rally-watcher/SKILL.md +83 -0
- package/skills/api-registry-bridge/SKILL.md +59 -0
- package/skills/architecture/dead/SKILL.md +56 -0
- package/skills/architecture/impact/SKILL.md +88 -0
- package/skills/architecture/review/SKILL.md +227 -0
- package/skills/architecture/rules/SKILL.md +72 -0
- package/skills/architecture/scan/SKILL.md +79 -0
- package/skills/architecture/trace/SKILL.md +65 -0
- package/skills/attribution-standard/SKILL.md +122 -0
- package/skills/authentication/SKILL.md +81 -0
- package/skills/authentication/references/better-auth-magic-link.md +135 -0
- package/skills/authentication/references/better-auth-setup.md +224 -0
- package/skills/authentication/references/google-calendar-sync.md +278 -0
- package/skills/authentication/references/google-cloud-console.md +159 -0
- package/skills/authentication/references/google-geocoding-directions.md +126 -0
- package/skills/authentication/references/google-lessons-example-web-app.md +177 -0
- package/skills/authentication/references/google-maps.md +162 -0
- package/skills/authentication/references/google-oauth-setup.md +343 -0
- package/skills/authentication/references/google-places.md +173 -0
- package/skills/authentication/references/lessons-example-web-app-better-auth.md +126 -0
- package/skills/authentication/references/resend-email.md +227 -0
- package/skills/authentication/references/resend-otp-magic-link.md +153 -0
- package/skills/authentication/references/supabase-auth.md +172 -0
- package/skills/auto-decision-capture/SKILL.md +419 -0
- package/skills/build-loop/SKILL.md +516 -0
- package/skills/build-loop/detect-plugins.mjs +82 -0
- package/skills/build-loop/eval-guide.md +65 -0
- package/skills/build-loop/fallbacks.md +549 -0
- package/skills/build-loop/phases/fact-check.md +42 -0
- package/skills/build-loop/phases/ui-validation.md +267 -0
- package/skills/build-loop/references/apple-native-planning.md +439 -0
- package/skills/build-loop/references/capability-routing.md +181 -0
- package/skills/build-loop/references/codex-subagents.md +98 -0
- package/skills/build-loop/references/coordination.md +161 -0
- package/skills/build-loop/references/correction-aware-capture.md +177 -0
- package/skills/build-loop/references/independent-auditor.md +72 -0
- package/skills/build-loop/references/intent-capability-pack.md +170 -0
- package/skills/build-loop/references/intent-exploration-prompts.md +96 -0
- package/skills/build-loop/references/leadership.md +72 -0
- package/skills/build-loop/references/memory.md +284 -0
- package/skills/build-loop/references/modular-systems-pack.md +96 -0
- package/skills/build-loop/references/output-style.md +129 -0
- package/skills/build-loop/references/pay-it-forward-arch.md +98 -0
- package/skills/build-loop/references/phase-1-assess.md +218 -0
- package/skills/build-loop/references/phase-2-plan.md +77 -0
- package/skills/build-loop/references/phase-3-execute.md +47 -0
- package/skills/build-loop/references/phase-4-review.md +310 -0
- package/skills/build-loop/references/phase-5-iterate.md +71 -0
- package/skills/build-loop/references/phase-6-learn.md +56 -0
- package/skills/build-loop/references/recent-design-structures.md +274 -0
- package/skills/build-loop/references/refactor-history/ASSESSMENT.md +85 -0
- package/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +149 -0
- package/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +32 -0
- package/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +48 -0
- package/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +60 -0
- package/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +51 -0
- package/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +71 -0
- package/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +52 -0
- package/skills/build-loop/references/refactor-history/trace-comparison.md +202 -0
- package/skills/build-loop/references/self-recursive-dev.md +77 -0
- package/skills/build-loop/references/self-review.md +232 -0
- package/skills/build-loop/references/ui-io-contract.md +116 -0
- package/skills/build-loop/scanners/audit-design-rules.mjs +476 -0
- package/skills/build-loop/scanners/require-visual-evidence.mjs +239 -0
- package/skills/build-loop/templates/backlog-item.md +35 -0
- package/skills/build-loop/templates/codex-worker-prompt.md +89 -0
- package/skills/build-loop/templates/ui-subagent-prompt.md +179 -0
- package/skills/build-loop/templates/ux-fix-plan.md +40 -0
- package/skills/building-with-deepagents/SKILL.md +195 -0
- package/skills/building-with-deepagents/references/anti-patterns.md +141 -0
- package/skills/building-with-deepagents/references/api-quick-reference.md +184 -0
- package/skills/capabilities/SKILL.md +91 -0
- package/skills/debug-loop/SKILL.md +278 -0
- package/skills/debug-loop/references/convergence-rules.md +145 -0
- package/skills/debug-loop/references/swiftui-macos-clunky-ui-debugger.html +823 -0
- package/skills/debugging/assess/SKILL.md +111 -0
- package/skills/debugging/debug-loop/SKILL.md +231 -0
- package/skills/debugging/memory/SKILL.md +147 -0
- package/skills/debugging/store/SKILL.md +153 -0
- package/skills/debugging-memory/SKILL.md +440 -0
- package/skills/debugging-memory/examples/incident-example.json +67 -0
- package/skills/debugging-memory/references/incident-documentation.md +280 -0
- package/skills/debugging-memory/references/ios-notification-alarm-playbook.md +300 -0
- package/skills/debugging-memory/references/pattern-extraction.md +163 -0
- package/skills/debugging-memory/references/subagent-integration.md +312 -0
- package/skills/defenseclaw-bridge/SKILL.md +156 -0
- package/skills/defenseclaw-bridge/references/dc-config-mapping.md +162 -0
- package/skills/defenseclaw-bridge/references/output-format.md +108 -0
- package/skills/handoff/SKILL.md +94 -0
- package/skills/ibr-bridge/SKILL.md +68 -0
- package/skills/knowledge/SKILL.md +127 -0
- package/skills/knowledge/references/recall-integration.md +83 -0
- package/skills/knowledge/templates/madr-minimal.md +56 -0
- package/skills/knowledge-review/SKILL.md +112 -0
- package/skills/logging-tracer/SKILL.md +202 -0
- package/skills/logging-tracer/references/log-analysis.md +128 -0
- package/skills/logging-tracer/references/stack-templates.md +274 -0
- package/skills/logging-tracer-bridge/SKILL.md +70 -0
- package/skills/mcp-builder/SKILL.md +278 -0
- package/skills/mcp-builder/references/mcp-security.md +106 -0
- package/skills/model-tiering/SKILL.md +216 -0
- package/skills/native-ax-driver/SKILL.md +220 -0
- package/skills/native-ax-driver/scripts/layout_fill.py +222 -0
- package/skills/native-ax-driver/scripts/native_driver.py +495 -0
- package/skills/native-ax-driver/swift/bl-ax-driver/Package.swift +20 -0
- package/skills/native-ax-driver/swift/bl-ax-driver/Sources/main.swift +542 -0
- package/skills/optimize/SKILL.md +202 -0
- package/skills/optimize/profiles.md +61 -0
- package/skills/plan-verify/SKILL.md +115 -0
- package/skills/plan-verify/test-fixtures/example-app-v20-findings.json +27 -0
- package/skills/plan-verify/test-fixtures/example-app-v20.md +42 -0
- package/skills/plan-verify/test-fixtures/example-app-v22-findings.json +15 -0
- package/skills/plan-verify/test-fixtures/example-app-v22.md +1608 -0
- package/skills/plan-verify/test-fixtures/unrelated-good-plan-findings.json +15 -0
- package/skills/plan-verify/test-fixtures/unrelated-good-plan.md +55 -0
- package/skills/plugin-builder/SKILL.md +329 -0
- package/skills/plugin-builder/references/authoritative-sources.md +104 -0
- package/skills/plugin-builder/references/build-loop-phase-guidance.md +94 -0
- package/skills/plugin-builder/references/components-guide.md +221 -0
- package/skills/plugin-builder/references/distribution.md +317 -0
- package/skills/plugin-builder/references/dual-host-claude-codex.md +220 -0
- package/skills/plugin-builder/references/hooks-reference.md +210 -0
- package/skills/plugin-builder/references/manifest-schema.md +111 -0
- package/skills/plugin-builder/references/plugin-hygiene-lessons.md +307 -0
- package/skills/plugin-tests/SKILL.md +94 -0
- package/skills/prd-bridge/SKILL.md +135 -0
- package/skills/research/SKILL.md +80 -0
- package/skills/security-methodology/SKILL.md +105 -0
- package/skills/security-methodology/references/cross-source-matrix.md +77 -0
- package/skills/security-methodology/references/mitre-atlas-starter.md +83 -0
- package/skills/security-methodology/references/nist-600-1-mapping.md +119 -0
- package/skills/security-methodology/references/owasp-agentic-top-10.md +157 -0
- package/skills/security-methodology/references/owasp-llm-top-10.md +144 -0
- package/skills/security-methodology/references/owasp-web-top-10.md +65 -0
- package/skills/self-improve/SKILL.md +298 -0
- package/skills/spec-writing/SKILL.md +548 -0
- package/skills/spec-writing/scripts/check_checklist.py +478 -0
- package/skills/sync-skills/SKILL.md +132 -0
- package/skills/telemetry/SKILL.md +66 -0
- package/skills/ui-design/SKILL.md +75 -0
- package/skills/ui-design/references/design-patterns-multi.md +165 -0
- package/skills/ui-design/references/design-preferences-from-owned-apps.md +150 -0
- package/skills/ui-design/references/evidence-capture-policy.md +55 -0
- package/skills/ui-design/references/ui-guidance-sources.md +330 -0
- package/skills/ui-design/references/universal-design-principles.alt.md +182 -0
- package/skills/ui-design/references/universal-design-principles.md +419 -0
- package/templates/memory/MEMORY.md.template +55 -0
- package/templates/memory/constitution.md.template +64 -0
- package/templates/memory/manifest.json +47 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
<!-- SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com> | SPDX-License-Identifier: Apache-2.0 -->
|
|
2
|
+
|
|
3
|
+
# Stack Templates — Logging & Tracing
|
|
4
|
+
|
|
5
|
+
## Node.js / TypeScript (Tier 1)
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// lib/logger.ts
|
|
9
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
10
|
+
|
|
11
|
+
const LEVELS: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
12
|
+
const MIN_LEVEL: LogLevel = (process.env.LOG_LEVEL as LogLevel) || 'info';
|
|
13
|
+
|
|
14
|
+
function log(level: LogLevel, op: string, data?: Record<string, unknown>) {
|
|
15
|
+
if (LEVELS[level] < LEVELS[MIN_LEVEL]) return;
|
|
16
|
+
const entry = { ts: Date.now(), level, op, ...data };
|
|
17
|
+
process.stderr.write(JSON.stringify(entry) + '\n');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function traced<T>(op: string, fn: () => Promise<T>, ctx?: Record<string, unknown>): Promise<T> {
|
|
21
|
+
const start = Date.now();
|
|
22
|
+
try {
|
|
23
|
+
const result = await fn();
|
|
24
|
+
log('info', op, { dur_ms: Date.now() - start, ...ctx });
|
|
25
|
+
return result;
|
|
26
|
+
} catch (err) {
|
|
27
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
28
|
+
log('error', op, { dur_ms: Date.now() - start, error: { name: e.name, message: e.message }, ...ctx });
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { log, traced, LogLevel };
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Usage
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { log, traced } from './lib/logger';
|
|
40
|
+
|
|
41
|
+
// Direct log
|
|
42
|
+
log('info', 'server:start', { port: 3000 });
|
|
43
|
+
|
|
44
|
+
// Wrap async operation
|
|
45
|
+
const user = await traced('db:getUser', () => db.user.findUnique({ where: { id } }), { userId: id });
|
|
46
|
+
|
|
47
|
+
// Error handling
|
|
48
|
+
try {
|
|
49
|
+
await riskyOperation();
|
|
50
|
+
} catch (err) {
|
|
51
|
+
log('error', 'payment:charge', {
|
|
52
|
+
error: { name: err.name, message: err.message },
|
|
53
|
+
customerId,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Node.js / TypeScript (Tier 2 — File Output)
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// lib/logger.ts
|
|
62
|
+
import { appendFileSync, statSync, renameSync, mkdirSync } from 'fs';
|
|
63
|
+
import { join } from 'path';
|
|
64
|
+
|
|
65
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
66
|
+
const LEVELS: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
67
|
+
const MIN_LEVEL: LogLevel = (process.env.LOG_LEVEL as LogLevel) || 'info';
|
|
68
|
+
|
|
69
|
+
const LOG_DIR = join(process.cwd(), 'logs');
|
|
70
|
+
const LOG_FILE = join(LOG_DIR, 'app.jsonl');
|
|
71
|
+
const MAX_SIZE = 10 * 1024 * 1024; // 10MB
|
|
72
|
+
const MAX_ROTATED = 2;
|
|
73
|
+
|
|
74
|
+
try { mkdirSync(LOG_DIR, { recursive: true }); } catch {}
|
|
75
|
+
|
|
76
|
+
function write(entry: Record<string, unknown>) {
|
|
77
|
+
try {
|
|
78
|
+
appendFileSync(LOG_FILE, JSON.stringify(entry) + '\n');
|
|
79
|
+
rotate();
|
|
80
|
+
} catch {}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function rotate() {
|
|
84
|
+
try {
|
|
85
|
+
const stat = statSync(LOG_FILE);
|
|
86
|
+
if (stat.size < MAX_SIZE) return;
|
|
87
|
+
for (let i = MAX_ROTATED; i >= 1; i--) {
|
|
88
|
+
try { renameSync(`${LOG_FILE}.${i}`, `${LOG_FILE}.${i + 1}`); } catch {}
|
|
89
|
+
}
|
|
90
|
+
renameSync(LOG_FILE, `${LOG_FILE}.1`);
|
|
91
|
+
} catch {}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function log(level: LogLevel, op: string, data?: Record<string, unknown>) {
|
|
95
|
+
if (LEVELS[level] < LEVELS[MIN_LEVEL]) return;
|
|
96
|
+
write({ ts: Date.now(), level, op, ...data });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function traced<T>(op: string, fn: () => Promise<T>, ctx?: Record<string, unknown>): Promise<T> {
|
|
100
|
+
const start = Date.now();
|
|
101
|
+
try {
|
|
102
|
+
const result = await fn();
|
|
103
|
+
log('info', op, { dur_ms: Date.now() - start, ...ctx });
|
|
104
|
+
return result;
|
|
105
|
+
} catch (err) {
|
|
106
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
107
|
+
log('error', op, { dur_ms: Date.now() - start, error: { name: e.name, message: e.message }, ...ctx });
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { log, traced };
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Python (Tier 1)
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
# lib/logger.py
|
|
119
|
+
import json, time, sys, os, functools
|
|
120
|
+
from typing import Any
|
|
121
|
+
|
|
122
|
+
LEVELS = {'debug': 0, 'info': 1, 'warn': 2, 'error': 3}
|
|
123
|
+
MIN_LEVEL = os.environ.get('LOG_LEVEL', 'info')
|
|
124
|
+
|
|
125
|
+
def log(level: str, op: str, **data: Any):
|
|
126
|
+
if LEVELS.get(level, 0) < LEVELS.get(MIN_LEVEL, 1):
|
|
127
|
+
return
|
|
128
|
+
entry = {'ts': int(time.time() * 1000), 'level': level, 'op': op, **data}
|
|
129
|
+
print(json.dumps(entry), file=sys.stderr)
|
|
130
|
+
|
|
131
|
+
def traced(op: str, **ctx):
|
|
132
|
+
def decorator(fn):
|
|
133
|
+
@functools.wraps(fn)
|
|
134
|
+
async def async_wrapper(*args, **kwargs):
|
|
135
|
+
start = time.time()
|
|
136
|
+
try:
|
|
137
|
+
result = await fn(*args, **kwargs)
|
|
138
|
+
log('info', op, dur_ms=int((time.time() - start) * 1000), **ctx)
|
|
139
|
+
return result
|
|
140
|
+
except Exception as e:
|
|
141
|
+
log('error', op, dur_ms=int((time.time() - start) * 1000),
|
|
142
|
+
error={'name': type(e).__name__, 'message': str(e)}, **ctx)
|
|
143
|
+
raise
|
|
144
|
+
|
|
145
|
+
@functools.wraps(fn)
|
|
146
|
+
def sync_wrapper(*args, **kwargs):
|
|
147
|
+
start = time.time()
|
|
148
|
+
try:
|
|
149
|
+
result = fn(*args, **kwargs)
|
|
150
|
+
log('info', op, dur_ms=int((time.time() - start) * 1000), **ctx)
|
|
151
|
+
return result
|
|
152
|
+
except Exception as e:
|
|
153
|
+
log('error', op, dur_ms=int((time.time() - start) * 1000),
|
|
154
|
+
error={'name': type(e).__name__, 'message': str(e)}, **ctx)
|
|
155
|
+
raise
|
|
156
|
+
|
|
157
|
+
import asyncio
|
|
158
|
+
if asyncio.iscoroutinefunction(fn):
|
|
159
|
+
return async_wrapper
|
|
160
|
+
return sync_wrapper
|
|
161
|
+
return decorator
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Usage
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from lib.logger import log, traced
|
|
168
|
+
|
|
169
|
+
log('info', 'server:start', port=8000)
|
|
170
|
+
|
|
171
|
+
@traced('db:get_user')
|
|
172
|
+
async def get_user(user_id: str):
|
|
173
|
+
return await db.users.find_one({"_id": user_id})
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Go (Tier 1)
|
|
177
|
+
|
|
178
|
+
```go
|
|
179
|
+
// pkg/logger/logger.go
|
|
180
|
+
package logger
|
|
181
|
+
|
|
182
|
+
import (
|
|
183
|
+
"encoding/json"
|
|
184
|
+
"fmt"
|
|
185
|
+
"os"
|
|
186
|
+
"strings"
|
|
187
|
+
"time"
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
var levels = map[string]int{"debug": 0, "info": 1, "warn": 2, "error": 3}
|
|
191
|
+
var minLevel = getEnvOr("LOG_LEVEL", "info")
|
|
192
|
+
|
|
193
|
+
type Entry struct {
|
|
194
|
+
Ts int64 `json:"ts"`
|
|
195
|
+
Level string `json:"level"`
|
|
196
|
+
Op string `json:"op"`
|
|
197
|
+
DurMs *int64 `json:"dur_ms,omitempty"`
|
|
198
|
+
Data map[string]interface{} `json:"data,omitempty"`
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
func Log(level, op string, data map[string]interface{}) {
|
|
202
|
+
if levels[level] < levels[minLevel] { return }
|
|
203
|
+
entry := Entry{Ts: time.Now().UnixMilli(), Level: level, Op: op, Data: data}
|
|
204
|
+
b, _ := json.Marshal(entry)
|
|
205
|
+
fmt.Fprintln(os.Stderr, string(b))
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
func Traced(op string, fn func() error) error {
|
|
209
|
+
start := time.Now()
|
|
210
|
+
if err := fn(); err != nil {
|
|
211
|
+
dur := time.Since(start).Milliseconds()
|
|
212
|
+
Log("error", op, map[string]interface{}{"dur_ms": dur, "error": err.Error()})
|
|
213
|
+
return err
|
|
214
|
+
}
|
|
215
|
+
dur := time.Since(start).Milliseconds()
|
|
216
|
+
Log("info", op, map[string]interface{}{"dur_ms": dur})
|
|
217
|
+
return nil
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
func getEnvOr(key, fallback string) string {
|
|
221
|
+
if v := os.Getenv(key); v != "" { return strings.ToLower(v) }
|
|
222
|
+
return fallback
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Node.js (Tier 3 — OpenTelemetry)
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// lib/tracing.ts
|
|
230
|
+
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
231
|
+
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
|
232
|
+
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
|
233
|
+
import { Resource } from '@opentelemetry/resources';
|
|
234
|
+
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
|
|
235
|
+
import { TraceIdRatioBasedSampler, ParentBasedSampler } from '@opentelemetry/sdk-trace-base';
|
|
236
|
+
|
|
237
|
+
// Prevent duplicate init in hot-reload
|
|
238
|
+
const INIT_KEY = Symbol.for('otel.initialized');
|
|
239
|
+
if ((globalThis as any)[INIT_KEY]) {
|
|
240
|
+
console.warn('[tracing] Already initialized, skipping');
|
|
241
|
+
} else {
|
|
242
|
+
const isDev = process.env.NODE_ENV !== 'production';
|
|
243
|
+
|
|
244
|
+
const sdk = new NodeSDK({
|
|
245
|
+
resource: new Resource({ [ATTR_SERVICE_NAME]: process.env.SERVICE_NAME || 'my-app' }),
|
|
246
|
+
traceExporter: new OTLPTraceExporter({
|
|
247
|
+
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318/v1/traces',
|
|
248
|
+
}),
|
|
249
|
+
sampler: new ParentBasedSampler({
|
|
250
|
+
root: new TraceIdRatioBasedSampler(isDev ? 1.0 : 0.1),
|
|
251
|
+
}),
|
|
252
|
+
instrumentations: [getNodeAutoInstrumentations()],
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
sdk.start();
|
|
256
|
+
(globalThis as any)[INIT_KEY] = true;
|
|
257
|
+
|
|
258
|
+
process.on('SIGTERM', () => sdk.shutdown());
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Required packages
|
|
263
|
+
```
|
|
264
|
+
@opentelemetry/sdk-node
|
|
265
|
+
@opentelemetry/exporter-trace-otlp-http
|
|
266
|
+
@opentelemetry/auto-instrumentations-node
|
|
267
|
+
@opentelemetry/resources
|
|
268
|
+
@opentelemetry/semantic-conventions
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Free backends
|
|
272
|
+
- **Jaeger** (local): `docker run -p 16686:16686 -p 4318:4318 jaegertracing/all-in-one`
|
|
273
|
+
- **SigNoz** (self-hosted): Follow docs at signoz.io
|
|
274
|
+
- **Grafana Tempo** (self-hosted): Pair with Grafana for UI
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-loop:logging-tracer-bridge
|
|
3
|
+
description: Use when the bundled logging-tracer skill signals insufficient tier-selection or codegen, or the user asks for "extended observability" or "cross-build log correlation". Optional escalation to standalone Coding Debugger for additional tracer backends and advanced placement intelligence.
|
|
4
|
+
version: 0.3.0
|
|
5
|
+
user-invocable: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<!-- SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com> | SPDX-License-Identifier: Apache-2.0 -->
|
|
9
|
+
|
|
10
|
+
# Logging-Tracer Bridge — Extended Capability Escalation
|
|
11
|
+
|
|
12
|
+
As of build-loop 0.7.1 this bridge's role is **escalation, not primary coordination**. The orchestrator owns when-to-fire (Phase 1 Assess observability scan, Phase 5 Iterate reactive trigger on `evidence_gap`) and routes those phases to the bundled internal `build-loop:logging-tracer` skill, which owns tier selection, stack detection, codegen, the ephemeral-by-default policy (Mechanisms A and B), and code-placement rules.
|
|
13
|
+
|
|
14
|
+
This bridge is the **secondary hop**: when the bundled logging-tracer decides it needs more than build-loop ships natively, it can invoke this bridge to delegate to standalone Coding Debugger (if installed) for extended observability tooling.
|
|
15
|
+
|
|
16
|
+
## When this bridge is invoked
|
|
17
|
+
|
|
18
|
+
By `build-loop:logging-tracer`, not the orchestrator. Calling sites:
|
|
19
|
+
|
|
20
|
+
- `build-loop:logging-tracer` §"Extended capability" — when the project requires a tracer backend or placement intelligence beyond what build-loop ships (e.g., a downstream MCP-discoverable log sink that lives in the standalone plugin only)
|
|
21
|
+
|
|
22
|
+
The orchestrator MUST NOT call this bridge directly. Orchestrator → `logging-tracer` skill → (optional) this bridge → standalone plugin.
|
|
23
|
+
|
|
24
|
+
## Pre-flight (always run first)
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
if (!state.availablePlugins.codingDebugger) {
|
|
28
|
+
return { delegated: false, reason: "standalone Coding Debugger plugin not installed" }
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If false, the calling target skill continues with bundled-only capability.
|
|
33
|
+
|
|
34
|
+
## Delegations available
|
|
35
|
+
|
|
36
|
+
| Capability needed | Standalone Skill / MCP call |
|
|
37
|
+
|---|---|
|
|
38
|
+
| Extended tracer backends not in bundle | `Skill("coding-debugger:logging-tracer")` with `tier: <upstream-only>` |
|
|
39
|
+
| Cross-build log correlation (e.g., correlation IDs across multiple build-loop runs) | standalone-only MCP tools |
|
|
40
|
+
| Advanced placement intelligence (e.g., function-call graph aware insertion) | standalone-only assessor skills |
|
|
41
|
+
|
|
42
|
+
The bridge passes through caller-supplied symptom + target-files + tier-hint, returns enriched data to `logging-tracer`. The target skill decides how to fold the extended result into its own codegen.
|
|
43
|
+
|
|
44
|
+
## What this bridge does NOT do
|
|
45
|
+
|
|
46
|
+
- Reimplement tier selection, stack detection, ephemeral mechanisms, or code placement — those live in `build-loop:logging-tracer`
|
|
47
|
+
- Replace the orchestrator's when-to-fire policy (Phase 1 Assess scan, Phase 5 Iterate evidence_gap trigger) — that lives in `agents/build-orchestrator.md`
|
|
48
|
+
- Introduce new logging dependencies without explicit user approval — that constraint stays in `logging-tracer`
|
|
49
|
+
- Mutate build-loop's native `.build-loop/issues/` paths
|
|
50
|
+
- Hard-fail when standalone is absent — pre-flight returns gracefully
|
|
51
|
+
|
|
52
|
+
## State
|
|
53
|
+
|
|
54
|
+
Optional bridge invocations are logged to `.build-loop/state.json.observability.escalations[]`:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{ "ts": "ISO", "calledBy": "logging-tracer", "reason": "tier_3_otel_required", "delegated": true|false }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Cross-references
|
|
61
|
+
|
|
62
|
+
- `agents/build-orchestrator.md` — when-to-fire policy (Phase 1 Assess scan, Phase 5 Iterate)
|
|
63
|
+
- `skills/logging-tracer/SKILL.md` — primary tier-selection / codegen / ephemeral-by-default skill
|
|
64
|
+
- `skills/build-loop/fallbacks.md` §`debug` — local-only fallback when neither bundled nor standalone is reachable
|
|
65
|
+
|
|
66
|
+
## History
|
|
67
|
+
|
|
68
|
+
- v0.2.0 — coordination layer (orchestrator called this bridge as primary entry point for observability)
|
|
69
|
+
- v0.7.0 — dissolved into `logging-tracer` skill + orchestrator (transient, in-flight architecture)
|
|
70
|
+
- v0.7.1 — restored as **extended-capability escalation hop** with the architecture documented above
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mcp-builder
|
|
3
|
+
description: Use when building, packaging, or debugging an MCP server, adding MCP tools to a plugin, or working on .mcp.json, transport, or bundling. Pair with plugin-builder when the plugin exposes MCP tools.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com> | SPDX-License-Identifier: Apache-2.0 -->
|
|
8
|
+
|
|
9
|
+
# MCP Builder
|
|
10
|
+
|
|
11
|
+
Build, bundle, and ship Model Context Protocol servers for Claude Code. Companion to `plugin-builder` — use both when the plugin exposes MCP tools.
|
|
12
|
+
|
|
13
|
+
## Doc lookup — api-registry first
|
|
14
|
+
|
|
15
|
+
Do **not** hardcode or fetch protocol-doc URLs from memory. Resolve them through the api-registry plugin's local doc cache:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
/api-registry:docs mcp-spec "<your question>" # MCP protocol spec
|
|
19
|
+
/api-registry:docs mcp-ts-sdk "<your question>" # TypeScript SDK
|
|
20
|
+
/api-registry:docs mcp-python-sdk "<your question>" # Python SDK
|
|
21
|
+
/api-registry:docs anthropic-plugins-reference "<your question>" # plugins-reference MCP section
|
|
22
|
+
/api-registry:docs mcp-servers "<your question>" # active reference servers
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
These registered services (`category: protocol`) carry authoritative `docs_url`s; api-registry answers from a dated local cache with a 7-day freshness contract and re-curates when stale. **Context7 MCP is the fallback only** — reached when no registered source exists. If the api-registry plugin is absent, fall back to the canonical URLs in the References section.
|
|
26
|
+
|
|
27
|
+
## Security preflight (mandatory)
|
|
28
|
+
|
|
29
|
+
Before writing any MCP server code, load `references/mcp-security.md` and run its inference + decision table. It produces a Tier 1 (always-mandatory) + Tier 2 (stage/type-gated) control checklist for *this* build. The checklist is **advisory** — it routes to the build-loop run report (Notes from judges / `state.json`), never an `AskUserQuestion` or hard gate. The `security-reviewer` agent grades the finished diff against the same matrix during Phase 4 Review-A.
|
|
30
|
+
|
|
31
|
+
## Scope split with plugin-builder
|
|
32
|
+
|
|
33
|
+
| Concern | Skill |
|
|
34
|
+
|---|---|
|
|
35
|
+
| Plugin directory layout, `plugin.json`, marketplace publishing | `plugin-builder` |
|
|
36
|
+
| MCP server implementation (protocol, tools, transport) | **this skill** |
|
|
37
|
+
| `.mcp.json` schema inside a plugin | both — schema lives in `plugin-builder/references/plugin-hygiene-lessons.md` |
|
|
38
|
+
| Bundling strategy (`tsup` vs `tsc` vs committed `dist/`) | **this skill** |
|
|
39
|
+
| Standalone MCP debugging | **this skill** |
|
|
40
|
+
|
|
41
|
+
## When to build an MCP server vs a hook vs a skill
|
|
42
|
+
|
|
43
|
+
| Use case | Choose |
|
|
44
|
+
|---|---|
|
|
45
|
+
| Expose a local database, filesystem, or API to Claude as callable tools | **MCP server** |
|
|
46
|
+
| React to Claude events (post-tool, session-stop, etc.) without exposing tools | **Hook** |
|
|
47
|
+
| Guide Claude with instructions/knowledge, no tool exposure | **Skill** |
|
|
48
|
+
| Wrap an existing CLI so Claude can invoke it | **MCP server** (thin wrapper) or **plugin bin/** if the CLI is already stable |
|
|
49
|
+
|
|
50
|
+
Don't build an MCP server when a skill + bash would suffice. The overhead is a separate process per server, JSON-RPC framing, and a config schema that's easy to get wrong.
|
|
51
|
+
|
|
52
|
+
## Server scaffold (TypeScript + stdio)
|
|
53
|
+
|
|
54
|
+
Use the official SDK. Stdio transport is default for Claude Code plugins.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// src/mcp/server.ts
|
|
58
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
59
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
60
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
61
|
+
|
|
62
|
+
const server = new Server(
|
|
63
|
+
{ name: 'my-plugin', version: '1.0.0' },
|
|
64
|
+
{ capabilities: { tools: {} } }
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
68
|
+
tools: [
|
|
69
|
+
{
|
|
70
|
+
name: 'echo',
|
|
71
|
+
description: 'Echo a message back',
|
|
72
|
+
inputSchema: {
|
|
73
|
+
type: 'object',
|
|
74
|
+
properties: { message: { type: 'string' } },
|
|
75
|
+
required: ['message'],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
82
|
+
if (req.params.name === 'echo') {
|
|
83
|
+
return { content: [{ type: 'text', text: String(req.params.arguments?.message) }] };
|
|
84
|
+
}
|
|
85
|
+
throw new Error(`Unknown tool: ${req.params.name}`);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const transport = new StdioServerTransport();
|
|
89
|
+
await server.connect(transport);
|
|
90
|
+
console.error('[my-plugin] MCP server started'); // stderr, not stdout
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Rules:**
|
|
94
|
+
- Log to `stderr` only. `stdout` is the JSON-RPC channel — anything else corrupts the protocol.
|
|
95
|
+
- Tool names: stable identifiers. Changing them is a breaking change for users.
|
|
96
|
+
- `inputSchema` is a JSON Schema. Be specific — vague schemas produce bad tool calls.
|
|
97
|
+
- Keep tool descriptions <500 chars; they're loaded into every session and cost tokens.
|
|
98
|
+
|
|
99
|
+
## Bundling: pick one (preferred → least preferred)
|
|
100
|
+
|
|
101
|
+
### 1. `tsup` — single-file bundle (strongly preferred)
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
// package.json
|
|
105
|
+
{
|
|
106
|
+
"scripts": { "build": "tsup src/mcp/server.ts --format=esm --target=node18 --bundle" },
|
|
107
|
+
"devDependencies": { "tsup": "^8", "@modelcontextprotocol/sdk": "^1" }
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Output: one self-contained `dist/mcp/server.js` that runs without `node_modules/`. Marketplaces can ship this without dependency resolution. IBR uses this pattern.
|
|
112
|
+
|
|
113
|
+
Commit `dist/` to git (don't gitignore) so the marketplace sync ships the bundle.
|
|
114
|
+
|
|
115
|
+
### 2. `tsc` + committed `dist/`
|
|
116
|
+
|
|
117
|
+
OK but fragile. Requires `node_modules/` at runtime, and marketplace sync skips `node_modules/`. Workarounds below.
|
|
118
|
+
|
|
119
|
+
### 3. `tsc` + SessionStart hook with `${CLAUDE_PLUGIN_DATA}`
|
|
120
|
+
|
|
121
|
+
Install deps into the persistent data dir the first time the plugin loads. Survives plugin updates.
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
// hooks/hooks.json
|
|
125
|
+
{
|
|
126
|
+
"hooks": {
|
|
127
|
+
"SessionStart": [{
|
|
128
|
+
"hooks": [{
|
|
129
|
+
"type": "command",
|
|
130
|
+
"command": "diff -q \"${CLAUDE_PLUGIN_ROOT}/package.json\" \"${CLAUDE_PLUGIN_DATA}/package.json\" >/dev/null 2>&1 || (cd \"${CLAUDE_PLUGIN_DATA}\" && cp \"${CLAUDE_PLUGIN_ROOT}/package.json\" . && npm install) || rm -f \"${CLAUDE_PLUGIN_DATA}/package.json\""
|
|
131
|
+
}]
|
|
132
|
+
}]
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Then point the MCP at the installed deps:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
// .mcp.json
|
|
141
|
+
{
|
|
142
|
+
"mcpServers": {
|
|
143
|
+
"my-plugin": {
|
|
144
|
+
"command": "node",
|
|
145
|
+
"args": ["${CLAUDE_PLUGIN_ROOT}/dist/mcp/server.js"],
|
|
146
|
+
"env": {
|
|
147
|
+
"NODE_PATH": "${CLAUDE_PLUGIN_DATA}/node_modules"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Trade-off: first session is slow (installs deps); subsequent sessions are instant.
|
|
155
|
+
|
|
156
|
+
### 4. Pure-stdlib Python server
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
# src/mcp/server.py — uses only the mcp package (can be vendored or single-file)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Works well when you want to avoid Node entirely. Harder to bundle single-file than TypeScript — usually needs `mcp-server-stdio` as a runtime dep.
|
|
163
|
+
|
|
164
|
+
## `.mcp.json` schema (the thing that breaks most often)
|
|
165
|
+
|
|
166
|
+
**CORRECT** — wrap in `"mcpServers"`:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"mcpServers": {
|
|
171
|
+
"my-plugin": {
|
|
172
|
+
"command": "node",
|
|
173
|
+
"args": ["${CLAUDE_PLUGIN_ROOT}/dist/mcp/server.js"],
|
|
174
|
+
"env": {
|
|
175
|
+
"DEBUG": "1"
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**WRONG** — flat form. Silently passes `/doctor`, fails at MCP startup. Only `/mcp` surfaces the error.
|
|
183
|
+
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"my-plugin": { "command": "node", "args": [...] }
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Real incident (2026-04-21): `bookmark`, `claude-code-debugger` both shipped flat `.mcp.json`. Both showed "MCP · ✗ failed" in `/plugin` for weeks before diagnosis. See `plugin-builder/references/plugin-hygiene-lessons.md` § 7.
|
|
191
|
+
|
|
192
|
+
### Inline form (in `plugin.json`)
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"name": "my-plugin",
|
|
197
|
+
"mcpServers": {
|
|
198
|
+
"my-plugin": { "command": "...", "args": [...] }
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Inline form drops the outer wrapper but uses the same inner structure.
|
|
204
|
+
|
|
205
|
+
## Standalone smoke test (before shipping)
|
|
206
|
+
|
|
207
|
+
Always verify the server responds to `initialize` before publishing. This isolates "server broken" from "Claude Code UI stale":
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | \
|
|
211
|
+
CLAUDE_PLUGIN_ROOT=/path/to/your/plugin \
|
|
212
|
+
node /path/to/your/plugin/dist/mcp/server.js
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Healthy response (single line of JSON):
|
|
216
|
+
```json
|
|
217
|
+
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-11-25","serverInfo":{"name":"my-plugin","version":"1.0.0"},"capabilities":{"tools":{}}}}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
If you see:
|
|
221
|
+
- nothing → server exited before the handshake; check `console.error` output
|
|
222
|
+
- `MODULE_NOT_FOUND` → bundling failed, `dist/` references a package that isn't bundled
|
|
223
|
+
- `EACCES` → file-permission issue, usually the script isn't executable (not required for `node` but often accompanies deeper path issues)
|
|
224
|
+
- `SyntaxError` → wrong target (e.g. ESM features in a CJS bundle, or vice versa)
|
|
225
|
+
|
|
226
|
+
The server should then block on stdin waiting for the next message. Send `Ctrl+D` (`echo ... | node ...` closes stdin after the echo, which is why the server exits cleanly).
|
|
227
|
+
|
|
228
|
+
## Debugging a failed server in Claude Code
|
|
229
|
+
|
|
230
|
+
1. Run the standalone smoke test above. If it fails, the server has a real problem.
|
|
231
|
+
2. If smoke test passes but `/plugin` still shows "failed", the UI status may be stale. Reload:
|
|
232
|
+
```
|
|
233
|
+
/reload-plugins
|
|
234
|
+
```
|
|
235
|
+
3. Check `/mcp` (more detail than `/plugin`). Look for the actual launch error.
|
|
236
|
+
4. Check `claude --debug` output at startup — logs every MCP init attempt.
|
|
237
|
+
5. Verify `${CLAUDE_PLUGIN_ROOT}` resolves to the right cache dir, not a stale one. Look at `~/.claude/plugins/installed_plugins.json` for the `installPath` of your plugin.
|
|
238
|
+
|
|
239
|
+
Common failure modes after the schema fix:
|
|
240
|
+
- **No `dist/` in the cache** — bundle wasn't committed, or was gitignored.
|
|
241
|
+
- **`node_modules/` missing** — using `tsc` pattern without the SessionStart-install hook.
|
|
242
|
+
- **Wrong `installPath`** — `version` field says 1.0.1 but `installPath` ends in `/1.0.0/`. See `plugin-hygiene-lessons.md` § 10.
|
|
243
|
+
|
|
244
|
+
## Tool design rules (for the MCP server itself)
|
|
245
|
+
|
|
246
|
+
1. **Few strong tools beats many weak tools.** Claude's tool-picking degrades with each added tool. Aim for <10 tools per server unless you genuinely expose a large surface.
|
|
247
|
+
2. **Idempotent by default.** Tool calls can be retried. Mutating operations should specify idempotency.
|
|
248
|
+
3. **Explicit outcome in return value.** Include status + structured data. "Returned successfully" with no payload hides silent failures.
|
|
249
|
+
4. **No network at startup.** Don't validate credentials in the constructor; do it in `initialize` or lazily on first tool call. Startup-time network == long `/plugin` load times.
|
|
250
|
+
5. **Respect timeouts.** MCP has a default request timeout. Long-running tools should either stream progress or return quickly with a handle the client can poll.
|
|
251
|
+
6. **Error messages are for the LLM.** Write errors Claude can use to self-correct: `"input 'path' must be absolute, got: './foo'"` beats `"InvalidPath"`.
|
|
252
|
+
|
|
253
|
+
## References
|
|
254
|
+
|
|
255
|
+
- `references/mcp-security.md` — NSA-derived stage-aware MCP security model (Tier 1 always-mandatory + Tier 2 decision table). Loaded by the Security preflight step above.
|
|
256
|
+
- `plugin-builder/references/plugin-hygiene-lessons.md` — real incidents, `.mcp.json` schema war stories, packaging traps (sections 7, 8, 11, 13)
|
|
257
|
+
|
|
258
|
+
**Doc sources** — resolve via `/api-registry:docs <service>` (primary path); the URLs below are the fallback only, used when the api-registry plugin is not installed:
|
|
259
|
+
|
|
260
|
+
- `mcp-spec` → https://modelcontextprotocol.io/specification — protocol spec
|
|
261
|
+
- `mcp-ts-sdk` → https://github.com/modelcontextprotocol/typescript-sdk — TypeScript reference SDK
|
|
262
|
+
- `mcp-python-sdk` → https://github.com/modelcontextprotocol/python-sdk — Python reference SDK
|
|
263
|
+
- `anthropic-plugins-reference` → https://code.claude.com/docs/en/plugins-reference#mcp-servers — Anthropic's MCP section
|
|
264
|
+
- `mcp-servers` / `mcp-servers-archived` → reference server lists (the archived list flags unsupported projects)
|
|
265
|
+
- https://github.com/tyroneross/interface-built-right — `tsup`-bundled example
|
|
266
|
+
|
|
267
|
+
## Preflight checklist (MCP-specific, supplements plugin-builder checklist)
|
|
268
|
+
|
|
269
|
+
- [ ] `.mcp.json` wraps servers in `{"mcpServers": {...}}`
|
|
270
|
+
- [ ] Command uses `${CLAUDE_PLUGIN_ROOT}` for all plugin-relative paths
|
|
271
|
+
- [ ] Bundled with `tsup` (single file) OR `dist/` + `${CLAUDE_PLUGIN_DATA}` install hook OR `dist/` committed with pure-stdlib
|
|
272
|
+
- [ ] `dist/` is NOT gitignored
|
|
273
|
+
- [ ] Server logs only to stderr (stdout reserved for protocol)
|
|
274
|
+
- [ ] Standalone smoke test via `initialize` RPC passes
|
|
275
|
+
- [ ] Tool count is appropriate (<10 unless necessary)
|
|
276
|
+
- [ ] No startup-time network calls
|
|
277
|
+
- [ ] Tool descriptions are concise (<500 chars each)
|
|
278
|
+
- [ ] Versioning: bump `plugin.json` and the `Server(...)` constructor's `version` together
|