@kryptosai/mcp-observatory 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/COMMERCIAL.md +6 -1
  2. package/CONTRIBUTORS.md +39 -0
  3. package/README.md +57 -18
  4. package/dist/src/adapters/http.js +1 -5
  5. package/dist/src/adapters/http.js.map +1 -1
  6. package/dist/src/cassette.js +3 -2
  7. package/dist/src/cassette.js.map +1 -1
  8. package/dist/src/checks/attack-sim.d.ts +18 -0
  9. package/dist/src/checks/attack-sim.js +304 -0
  10. package/dist/src/checks/attack-sim.js.map +1 -0
  11. package/dist/src/ci-issue.js +4 -3
  12. package/dist/src/ci-issue.js.map +1 -1
  13. package/dist/src/cli.js +17 -3
  14. package/dist/src/cli.js.map +1 -1
  15. package/dist/src/commands/attack-sim.d.ts +2 -0
  16. package/dist/src/commands/attack-sim.js +168 -0
  17. package/dist/src/commands/attack-sim.js.map +1 -0
  18. package/dist/src/commands/init-ci.d.ts +1 -0
  19. package/dist/src/commands/init-ci.js +8 -3
  20. package/dist/src/commands/init-ci.js.map +1 -1
  21. package/dist/src/commands/legacy.js +6 -1
  22. package/dist/src/commands/legacy.js.map +1 -1
  23. package/dist/src/commands/scan.js +7 -1
  24. package/dist/src/commands/scan.js.map +1 -1
  25. package/dist/src/commands/serve.js +9 -1
  26. package/dist/src/commands/serve.js.map +1 -1
  27. package/dist/src/commands/setup-ci-conversion.d.ts +1 -0
  28. package/dist/src/commands/setup-ci-conversion.js +1 -0
  29. package/dist/src/commands/setup-ci-conversion.js.map +1 -1
  30. package/dist/src/commands/telemetry.js +20 -14
  31. package/dist/src/commands/telemetry.js.map +1 -1
  32. package/dist/src/commands/test.js +13 -1
  33. package/dist/src/commands/test.js.map +1 -1
  34. package/dist/src/findings.js +41 -1
  35. package/dist/src/findings.js.map +1 -1
  36. package/dist/src/history.js +3 -2
  37. package/dist/src/history.js.map +1 -1
  38. package/dist/src/index.d.ts +2 -0
  39. package/dist/src/index.js +2 -0
  40. package/dist/src/index.js.map +1 -1
  41. package/dist/src/integrations/smithery.js +5 -1
  42. package/dist/src/integrations/smithery.js.map +1 -1
  43. package/dist/src/reporters/attack-sim.d.ts +2 -0
  44. package/dist/src/reporters/attack-sim.js +84 -0
  45. package/dist/src/reporters/attack-sim.js.map +1 -0
  46. package/dist/src/reporters/pr-comment.js +20 -6
  47. package/dist/src/reporters/pr-comment.js.map +1 -1
  48. package/dist/src/runner.d.ts +3 -0
  49. package/dist/src/runner.js +5 -0
  50. package/dist/src/runner.js.map +1 -1
  51. package/dist/src/score.js +1 -1
  52. package/dist/src/score.js.map +1 -1
  53. package/dist/src/storage.js +3 -2
  54. package/dist/src/storage.js.map +1 -1
  55. package/dist/src/telemetry.d.ts +3 -0
  56. package/dist/src/telemetry.js +17 -1
  57. package/dist/src/telemetry.js.map +1 -1
  58. package/dist/src/types.d.ts +1 -1
  59. package/dist/src/utils/files.d.ts +1 -0
  60. package/dist/src/utils/files.js +21 -0
  61. package/dist/src/utils/files.js.map +1 -0
  62. package/dist/src/utils/ids.js +18 -5
  63. package/dist/src/utils/ids.js.map +1 -1
  64. package/dist/src/utils/url.d.ts +2 -0
  65. package/dist/src/utils/url.js +15 -0
  66. package/dist/src/utils/url.js.map +1 -0
  67. package/dist/src/validate.js +1 -1
  68. package/dist/src/validate.js.map +1 -1
  69. package/docs/agent-ecosystem-promotion-plan.md +244 -0
  70. package/docs/agent-tasks.md +95 -0
  71. package/docs/automatic-ci-integration.md +33 -0
  72. package/docs/campaign-attribution.md +58 -0
  73. package/docs/code-scanning-demo.md +57 -0
  74. package/docs/contributor-proof-cards/README.md +33 -0
  75. package/docs/contributor-recognition.md +92 -0
  76. package/docs/feishu-lark-mcp.md +1 -1
  77. package/docs/github-code-scanning-for-mcp.md +1 -1
  78. package/docs/launch.md +64 -0
  79. package/docs/mcp-attack-simulator.md +57 -0
  80. package/docs/mcp-server-safety-index.md +18 -12
  81. package/docs/proof.md +5 -2
  82. package/docs/receipt-graph.md +54 -0
  83. package/docs/safety-index/artifacts/antv-chart-server.json +21 -21
  84. package/docs/safety-index/artifacts/antv-chart-server.md +10 -10
  85. package/docs/safety-index/artifacts/browsermcp-server.json +17 -17
  86. package/docs/safety-index/artifacts/browsermcp-server.md +10 -10
  87. package/docs/safety-index/artifacts/context7-server.json +17 -17
  88. package/docs/safety-index/artifacts/context7-server.md +10 -10
  89. package/docs/safety-index/artifacts/cyanheads-git-mcp-server.json +2014 -0
  90. package/docs/safety-index/artifacts/cyanheads-git-mcp-server.md +163 -0
  91. package/docs/safety-index/artifacts/everything-server.json +131 -56
  92. package/docs/safety-index/artifacts/everything-server.md +24 -24
  93. package/docs/safety-index/artifacts/executeautomation-playwright-server.json +26 -18
  94. package/docs/safety-index/artifacts/executeautomation-playwright-server.md +10 -10
  95. package/docs/safety-index/artifacts/filesystem-server.json +128 -20
  96. package/docs/safety-index/artifacts/filesystem-server.md +10 -10
  97. package/docs/safety-index/artifacts/kubernetes-server.attack.json +1559 -0
  98. package/docs/safety-index/artifacts/kubernetes-server.attack.md +43 -0
  99. package/docs/safety-index/artifacts/kubernetes-server.attack.sarif +2857 -0
  100. package/docs/safety-index/artifacts/kubernetes-server.json +1348 -0
  101. package/docs/safety-index/artifacts/kubernetes-server.md +150 -0
  102. package/docs/safety-index/artifacts/memory-server.json +75 -32
  103. package/docs/safety-index/artifacts/memory-server.md +35 -28
  104. package/docs/safety-index/artifacts/opentofu-server.json +25 -17
  105. package/docs/safety-index/artifacts/opentofu-server.md +11 -11
  106. package/docs/safety-index/artifacts/playwright-mcp-server.json +56 -20
  107. package/docs/safety-index/artifacts/playwright-mcp-server.md +12 -12
  108. package/docs/safety-index/artifacts/promptopia-server.json +28 -20
  109. package/docs/safety-index/artifacts/promptopia-server.md +11 -11
  110. package/docs/safety-index/artifacts/puppeteer-server.json +42 -30
  111. package/docs/safety-index/artifacts/puppeteer-server.md +28 -28
  112. package/docs/safety-index/artifacts/ref-tools-server.json +17 -17
  113. package/docs/safety-index/artifacts/ref-tools-server.md +9 -9
  114. package/docs/safety-index/artifacts/sequential-thinking-server.json +20 -21
  115. package/docs/safety-index/artifacts/sequential-thinking-server.md +10 -10
  116. package/docs/safety-index/targets.json +90 -14
  117. package/docs/setup-ci-doctor.md +2 -0
  118. package/docs/target-gallery.md +49 -0
  119. package/docs/target-registry.md +5 -1
  120. package/docs/tool-call-receipts.md +116 -0
  121. package/package.json +20 -2
  122. package/schemas/run-artifact.schema.json +1 -0
  123. package/scripts/postinstall.mjs +123 -0
@@ -0,0 +1,49 @@
1
+ # Target Gallery
2
+
3
+ The Target Gallery turns the Safety Index into a maintainer-friendly map of the MCP ecosystem. It is not a leaderboard. It groups examples by the kind of agent dependency risk they represent.
4
+
5
+ For reproducible evidence, see the [MCP Server Safety Index](./mcp-server-safety-index.md). For contributor credit attached to accepted targets, see [MCP Observatory Contributors](./contributor-recognition.md) and [Contributor Proof Cards](./contributor-proof-cards/).
6
+
7
+ ## Reference And Baseline Servers
8
+
9
+ | Target | Why Agents Care | Next Step |
10
+ | --- | --- | --- |
11
+ | Official everything server | Broad MCP protocol surface across tools, prompts, and resources | Keep as a baseline compatibility target |
12
+ | Official sequential thinking server | Small tool surface with readable schemas | Use as a simple CI starter target |
13
+ | Official memory server | Agent-facing persistent state | Watch schema and write boundaries |
14
+
15
+ ## Filesystem, Browser, And Execution Boundaries
16
+
17
+ | Target | Why Agents Care | Next Step |
18
+ | --- | --- | --- |
19
+ | Official filesystem server | File access boundaries need harmless test roots | Review path scope before production |
20
+ | BrowserMCP | Browser-control tools can affect live sessions | Add read-only CI before agent rollout |
21
+ | Microsoft Playwright MCP | Browser automation can cross into code execution policy | Treat findings as policy review prompts |
22
+ | Puppeteer MCP server | Browser automation needs clear execution boundaries | Keep intentional browser checks explicit |
23
+ | ExecuteAutomation Playwright MCP | Startup/listing reproducibility affects agent trust | Start with maintainer conversation |
24
+
25
+ ## Retrieval, Documentation, And Prompt Surfaces
26
+
27
+ | Target | Why Agents Care | Next Step |
28
+ | --- | --- | --- |
29
+ | Context7 | Retrieval tools can move untrusted text into agent context | Add drift and schema checks |
30
+ | Promptopia | Prompt/resource contracts shape agent behavior | Keep generated evidence current |
31
+ | Ref tools | Developer-tool inventory should stay stable | Add CI and badge proof |
32
+
33
+ ## Infrastructure And Artifact-Producing Tools
34
+
35
+ | Target | Why Agents Care | Next Step |
36
+ | --- | --- | --- |
37
+ | OpenTofu MCP server | Infrastructure tools can influence production changes | Run checks before unattended agents use it |
38
+ | AntV chart MCP server | Artifact-producing tools need clear schemas and outputs | Keep CI evidence public |
39
+
40
+ ## Add A Target
41
+
42
+ Use the [target contribution guide](./target-contribution-guide.md). The best target has a public package, no secrets, no paid dependency, and a harmless startup command.
43
+
44
+ ```bash
45
+ npm run safety-index
46
+ npm test -- tests/safety-index.test.ts
47
+ ```
48
+
49
+ Accepted target PRs can receive a Target Scout or Target Verifier role, an All Contributors entry, and a proof card under `docs/contributor-proof-cards/` that links to the merged PR and generated public evidence.
@@ -23,6 +23,7 @@ Every accepted target creates several useful surfaces:
23
23
  - JSON and Markdown evidence artifacts
24
24
  - a maintainer conversation starter
25
25
  - a badge or CI adoption path
26
+ - contributor recognition and a proof-card link
26
27
  - a small contribution that another agent can copy
27
28
 
28
29
  That means one tiny PR can produce docs, evidence, search surface, backlinks, and future issues.
@@ -89,10 +90,13 @@ Add one object to `docs/safety-index/targets.json`:
89
90
  3. Add one target entry.
90
91
  4. Run the Safety Index locally.
91
92
  5. Open a small PR with the target and generated evidence.
92
- 6. Optionally ask the maintainer if they want an Observatory badge or CI check.
93
+ 6. Add or request a contributor proof card.
94
+ 7. Optionally ask the maintainer if they want an Observatory badge or CI check.
93
95
 
94
96
  Use the detailed walkthrough in [Target Contribution Guide](./target-contribution-guide.md).
95
97
 
98
+ Accepted target contributions can receive a role on [MCP Observatory Contributors](./contributor-recognition.md), an All Contributors entry, and a Markdown proof card under [`docs/contributor-proof-cards/`](./contributor-proof-cards/).
99
+
96
100
  ## Contribution Queue
97
101
 
98
102
  Ready-made target tasks live under the [`target-registry` label](https://github.com/KryptosAI/mcp-observatory/issues?q=is%3Aissue%20is%3Aopen%20label%3Atarget-registry). Pick one issue, make one small PR, and include generated evidence.
@@ -0,0 +1,116 @@
1
+ # Tool-Call Receipts
2
+
3
+ MCP servers need receipts, not badges.
4
+
5
+ A badge says a project wants trust. A receipt shows what was checked, what could have happened, what could not have happened, and which artifact a maintainer or security team can rerun.
6
+
7
+ Use this page when turning MCP Observatory results into Safety Index entries, maintainer PRs, SARIF uploads, proof cards, or private dependency reviews.
8
+
9
+ ## Receipt Fields
10
+
11
+ A useful receipt should identify:
12
+
13
+ | Field | Purpose |
14
+ | --- | --- |
15
+ | `maintainer` | Public project, package, or account responsible for the server. |
16
+ | `source` | Public repo, package, version, and safe startup command. |
17
+ | `observatory` | MCP Observatory version, command, mode, and report timestamp. |
18
+ | `capabilityEnvelope` | What the simulation could and could not access. |
19
+ | `call` | Tool-listing, schema, prompt, resource, or safe invocation surface inspected. |
20
+ | `reason` | Why the check matters for agents depending on the server. |
21
+ | `result` | Verdict, severity, normalized findings, and maintainer-facing recommendation. |
22
+ | `changedArtifact` | JSON, Markdown, SARIF, hash, or PR evidence generated from the run. |
23
+ | `baseline` | Previous run, lock file, or Safety Index entry used for drift comparison. |
24
+ | `safeModeConstraints` | Explicit limits proving the receipt did not run destructive probes. |
25
+
26
+ Example shape:
27
+
28
+ ```json
29
+ {
30
+ "maintainer": "Example MCP Server",
31
+ "source": {
32
+ "repo": "https://github.com/example/mcp-server",
33
+ "command": "npx -y example-mcp-server"
34
+ },
35
+ "observatory": {
36
+ "version": "0.28.0",
37
+ "mode": "safe",
38
+ "command": "mcp-observatory attack-sim npx -y example-mcp-server"
39
+ },
40
+ "capabilityEnvelope": {
41
+ "filesystem": "fixture-only",
42
+ "network": "not invoked",
43
+ "shell": "not available to probes",
44
+ "credentials": "none"
45
+ },
46
+ "call": {
47
+ "type": "tools/list"
48
+ },
49
+ "reason": "permission-boundary risk",
50
+ "result": {
51
+ "severity": "medium",
52
+ "evidence": "Tool schema accepts broad path input and advertises write behavior."
53
+ },
54
+ "changedArtifact": {
55
+ "json": "docs/safety-index/artifacts/example.attack.json",
56
+ "sarif": "docs/safety-index/artifacts/example.attack.sarif"
57
+ },
58
+ "baseline": {
59
+ "id": "previous-safety-index-run"
60
+ },
61
+ "safeModeConstraints": [
62
+ "No destructive tool calls",
63
+ "No external exfiltration",
64
+ "No credential probing",
65
+ "No writes outside checked-in fixtures"
66
+ ]
67
+ }
68
+ ```
69
+
70
+ ## Capability Envelope
71
+
72
+ Every public receipt should explain the boundary of the run. For agent safety, the absence of a dangerous capability is as important as the finding itself.
73
+
74
+ At minimum, state whether the run had access to:
75
+
76
+ - Filesystem writes or deletes
77
+ - Network calls
78
+ - Shell or process execution
79
+ - Credentials, tokens, cookies, or production services
80
+ - Real user data
81
+ - Fixture data only
82
+
83
+ For public Safety Index evidence, prefer `attack-sim --mode safe`, public packages, checked-in fixtures, and no-secret startup commands. If a server requires private credentials, keep that evidence out of the public index and treat it as a private readiness review.
84
+
85
+ ## How Observatory Produces Receipts
86
+
87
+ Use these commands as the receipt ladder:
88
+
89
+ ```bash
90
+ npx @kryptosai/mcp-observatory test npx -y my-mcp-server --json run-artifact.json --markdown run-report.md
91
+ npx @kryptosai/mcp-observatory attack-sim npx -y my-mcp-server --json attack-artifact.json --output attack-report.md --sarif attack-results.sarif
92
+ npx @kryptosai/mcp-observatory setup-ci --all --command "npx -y my-mcp-server" --sarif
93
+ ```
94
+
95
+ The normal run artifact shows protocol readiness. The attack-sim artifact shows safe attack-readiness evidence for tool poisoning, exfiltration canaries, permission-boundary risk, and drift readiness. The CI setup turns the receipt into something a maintainer can keep rerunning.
96
+
97
+ ## Safety Index Rules
98
+
99
+ Public Safety Index entries must use:
100
+
101
+ - Public repos, public packages, or public startup commands
102
+ - Sanitized JSON, Markdown, and SARIF artifacts
103
+ - Safe-mode attack simulation only
104
+ - Maintainer-friendly recommendations
105
+ - No private telemetry, secrets, hostnames, customer data, emails, or unpublished claims
106
+
107
+ Rough PRs are welcome at intake. Published entries should be normalized into receipts a maintainer can reproduce.
108
+
109
+ ## Contributor Prompt
110
+
111
+ Use this when inviting agents, bot authors, and MCP maintainers to contribute:
112
+
113
+ ```text
114
+ Name one MCP server your agent depends on. I will help turn it into a reproducible tool-call receipt: safe startup command, run artifact, attack-sim evidence, SARIF, and a CI gate maintainers can review.
115
+ ```
116
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kryptosai/mcp-observatory",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "description": "GitHub-native CI, SARIF, Code Scanning, and security gates for MCP servers before agents depend on them.",
5
5
  "mcpName": "io.github.KryptosAI/mcp-observatory",
6
6
  "license": "MIT",
@@ -33,18 +33,28 @@
33
33
  "README.md",
34
34
  "CLONED_THIS.md",
35
35
  "COMMERCIAL.md",
36
+ "CONTRIBUTORS.md",
36
37
  "PRIVACY.md",
37
38
  "TERMS.md",
38
39
  "LICENSE",
39
40
  "docs/agent-runtime-quickstart.md",
41
+ "docs/agent-ecosystem-promotion-plan.md",
42
+ "docs/agent-tasks.md",
43
+ "docs/automatic-ci-integration.md",
40
44
  "docs/architecture.md",
45
+ "docs/campaign-attribution.md",
46
+ "docs/code-scanning-demo.md",
41
47
  "docs/code-scanning-launch-outreach.md",
42
48
  "docs/compatibility.md",
49
+ "docs/contributor-proof-cards",
50
+ "docs/contributor-recognition.md",
43
51
  "docs/decisions.md",
44
52
  "docs/demo.svg",
45
53
  "docs/feishu-lark-mcp.md",
46
54
  "docs/github-code-scanning-for-mcp.md",
47
55
  "docs/known-issues.md",
56
+ "docs/launch.md",
57
+ "docs/mcp-attack-simulator.md",
48
58
  "docs/mcp-lock-files.md",
49
59
  "docs/mcp-safety-field-report-2026-06.md",
50
60
  "docs/mcp-safety-report-latest.md",
@@ -54,11 +64,15 @@
54
64
  "docs/metrics-dashboard.md",
55
65
  "docs/openclaw-agent-template",
56
66
  "docs/proof.md",
67
+ "docs/receipt-graph.md",
57
68
  "docs/reference-evaluations.md",
58
69
  "docs/safety-index",
59
70
  "docs/setup-ci-doctor.md",
60
71
  "docs/target-contribution-guide.md",
72
+ "docs/target-gallery.md",
61
73
  "docs/target-registry.md",
74
+ "docs/tool-call-receipts.md",
75
+ "scripts/postinstall.mjs",
62
76
  "schemas"
63
77
  ],
64
78
  "scripts": {
@@ -74,11 +88,13 @@
74
88
  "safety-index": "tsx scripts/run-safety-index.ts",
75
89
  "lint": "eslint .",
76
90
  "prepack": "npm run build",
91
+ "postinstall": "node scripts/postinstall.mjs",
77
92
  "proof:refresh": "tsx scripts/refresh-proof-artifacts.ts",
78
93
  "release:prep": "node scripts/release.mjs",
79
94
  "certification:pr-body": "tsx scripts/print-certification-pr-body.ts",
80
95
  "typecheck": "tsc --noEmit -p tsconfig.json && npm --prefix api install && npm --prefix api run typecheck",
81
96
  "test": "vitest run",
97
+ "test:coverage": "vitest run --coverage",
82
98
  "validate:artifacts": "tsx scripts/validate-artifacts.ts",
83
99
  "verify:packed-install": "node scripts/verify-packed-install.mjs",
84
100
  "smoke": "npm run cli -- run --target tests/fixtures/sample-target-config.json && npm run cli -- diff tests/fixtures/sample-run-a.json tests/fixtures/sample-run-b.json",
@@ -120,7 +136,8 @@
120
136
  "enterprise-report",
121
137
  "feishu",
122
138
  "lark",
123
- "schema-drift"
139
+ "schema-drift",
140
+ "attack-simulation"
124
141
  ],
125
142
  "dependencies": {
126
143
  "@modelcontextprotocol/sdk": "^1.29.0",
@@ -138,6 +155,7 @@
138
155
  "eslint": "10.6.0",
139
156
  "globals": "17.7.0",
140
157
  "tsx": "4.22.4",
158
+ "@vitest/coverage-v8": "4.1.9",
141
159
  "typescript": "6.0.3",
142
160
  "typescript-eslint": "8.62.1",
143
161
  "vitest": "4.1.9"
@@ -49,6 +49,7 @@
49
49
  "tools-invoke",
50
50
  "security",
51
51
  "security-lite",
52
+ "attack-sim",
52
53
  "conformance",
53
54
  "schema-quality"
54
55
  ]
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env node
2
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
7
+ const projectRoot = path.resolve(process.env.INIT_CWD || process.cwd());
8
+ const isSelfInstall = projectRoot === packageRoot || projectRoot.startsWith(`${packageRoot}${path.sep}`);
9
+ const disabled = process.env.MCP_OBSERVATORY_POSTINSTALL === "0" ||
10
+ process.env.MCP_OBSERVATORY_DISABLE_POSTINSTALL === "1";
11
+ const forceAuto = process.env.MCP_OBSERVATORY_AUTO_SETUP_CI === "1";
12
+ const isCi = process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
13
+
14
+ function readJson(filePath) {
15
+ try {
16
+ return JSON.parse(readFileSync(filePath, "utf8"));
17
+ } catch {
18
+ return undefined;
19
+ }
20
+ }
21
+
22
+ function hasOwn(value, key) {
23
+ return Object.prototype.hasOwnProperty.call(value || {}, key);
24
+ }
25
+
26
+ function isLikelyMcpProject(pkg) {
27
+ const keywords = Array.isArray(pkg?.keywords) ? pkg.keywords.map(String) : [];
28
+ const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}), ...(pkg?.peerDependencies || {}) };
29
+ return Boolean(pkg?.mcpName) ||
30
+ keywords.some((keyword) => /^(mcp|mcp-server|model-context-protocol)$/i.test(keyword)) ||
31
+ hasOwn(deps, "@modelcontextprotocol/sdk") ||
32
+ Object.keys(pkg?.scripts || {}).some((name) => /(^|:)mcp($|:|-)/i.test(name));
33
+ }
34
+
35
+ function inferCommand(pkg, config) {
36
+ if (process.env.MCP_OBSERVATORY_TARGET_COMMAND) return process.env.MCP_OBSERVATORY_TARGET_COMMAND;
37
+ if (typeof config?.command === "string" && config.command.trim()) return config.command.trim();
38
+ const scripts = pkg?.scripts || {};
39
+ for (const name of ["mcp", "start:mcp", "server:mcp", "mcp:serve", "dev:mcp"]) {
40
+ if (typeof scripts[name] === "string") return `npm run ${name}`;
41
+ }
42
+ if (typeof pkg?.name === "string" && pkg.name.trim()) return `npx -y ${pkg.name}`;
43
+ return "npx -y <server-package>";
44
+ }
45
+
46
+ function yamlString(value) {
47
+ return JSON.stringify(value);
48
+ }
49
+
50
+ function yamlFor(command, sarif) {
51
+ return [
52
+ "name: MCP Observatory",
53
+ "",
54
+ "on:",
55
+ " pull_request:",
56
+ " push:",
57
+ " branches: [main]",
58
+ "",
59
+ "permissions:",
60
+ " contents: read",
61
+ ...(sarif ? [" security-events: write"] : []),
62
+ "",
63
+ "jobs:",
64
+ " mcp-observatory:",
65
+ " runs-on: ubuntu-latest",
66
+ " steps:",
67
+ " - uses: actions/checkout@v6",
68
+ " - uses: KryptosAI/mcp-observatory/action@v0.27.0",
69
+ " with:",
70
+ ` command: ${yamlString(command)}`,
71
+ " deep: true",
72
+ " security: true",
73
+ " comment-on-pr: false",
74
+ " set-status: false",
75
+ ...(sarif ? [" upload-sarif: true"] : []),
76
+ " # Generated by @kryptosai/mcp-observatory postinstall.",
77
+ "",
78
+ ].join("\n");
79
+ }
80
+
81
+ function writeCi(projectRoot, command, sarif) {
82
+ const workflowPath = path.join(projectRoot, ".github", "workflows", "mcp-observatory.yml");
83
+ mkdirSync(path.dirname(workflowPath), { recursive: true });
84
+ try {
85
+ writeFileSync(workflowPath, yamlFor(command, sarif), { encoding: "utf8", flag: "wx" });
86
+ return { status: "created", workflowPath };
87
+ } catch (error) {
88
+ if (error && typeof error === "object" && "code" in error && error.code === "EEXIST") {
89
+ return { status: "exists", workflowPath };
90
+ }
91
+ throw error;
92
+ }
93
+ }
94
+
95
+ function log(message) {
96
+ process.stderr.write(`${message}\n`);
97
+ }
98
+
99
+ try {
100
+ if (disabled || isSelfInstall || isCi) process.exit(0);
101
+
102
+ const pkg = readJson(path.join(projectRoot, "package.json"));
103
+ if (!pkg || !isLikelyMcpProject(pkg)) process.exit(0);
104
+
105
+ const config = pkg.mcpObservatory && typeof pkg.mcpObservatory === "object" ? pkg.mcpObservatory : {};
106
+ const command = inferCommand(pkg, config);
107
+ const sarif = config.sarif === true || process.env.MCP_OBSERVATORY_AUTO_SETUP_SARIF === "1";
108
+ const autoSetup = forceAuto || config.autoSetupCi === true;
109
+
110
+ if (autoSetup) {
111
+ const result = writeCi(projectRoot, command, sarif);
112
+ const relative = path.relative(projectRoot, result.workflowPath);
113
+ log(result.status === "created"
114
+ ? `MCP Observatory: created ${relative}. Verify with: npx @kryptosai/mcp-observatory setup-ci --doctor`
115
+ : `MCP Observatory: ${relative} already exists. Verify with: npx @kryptosai/mcp-observatory setup-ci --doctor`);
116
+ } else {
117
+ log(`MCP Observatory: CI ready. Run: npx @kryptosai/mcp-observatory setup-ci --all --command "${command.replaceAll("\"", "\\\"")}"${sarif ? " --sarif" : ""}`);
118
+ log("MCP Observatory: to auto-create CI on install, set package.json mcpObservatory.autoSetupCi=true.");
119
+ }
120
+ } catch (error) {
121
+ const message = error instanceof Error ? error.message : String(error);
122
+ log(`MCP Observatory: install-time CI helper skipped (${message}).`);
123
+ }