Compare commits

..
47 Commits
Author SHA1 Message Date
github-actions[bot] 7dd46b8532 chore: update OpenSSF Scorecard badge 2026-10-28 13:22:31 +00:00
DevidandGitHub 2a6cd8015a Merge pull request #16 from masdevid/dependabot/github_actions/github-actions-af0bba1cf7
chore(deps): bump the github-actions group with 5 updates
2026-10-14 10:01:31 +07:00
DevidandGitHub 4216d704cd Merge pull request #18 from masdevid/dependabot/cargo/minor-and-patch-335c3d52a5
chore(deps): bump the minor-and-patch group across 1 directory with 4 updates
2026-10-14 10:01:09 +07:00
dependabot[bot]andGitHub 9ddabff95a chore(deps): bump the minor-and-patch group across 1 directory with 4 updates
Bumps the minor-and-patch group with 4 updates in the / directory: [tokio](https://github.com/tokio-rs/tokio), [clap](https://github.com/clap-rs/clap), [uuid](https://github.com/uuid-rs/uuid) and [encoding_rs](https://github.com/hsivonen/encoding_rs).


Updates `tokio` from 1.53.1 to 1.53.2
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.53.1...tokio-1.53.2)

Updates `clap` from 4.6.6 to 4.6.7
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/main/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.6.6...clap_complete-v4.6.7)

Updates `uuid` from 1.26.1 to 1.27.0
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.26.1...v1.27.0)

Updates `encoding_rs` from 0.8.41 to 0.8.42
- [Commits](https://github.com/hsivonen/encoding_rs/compare/v0.8.41...v0.8.42)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.53.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: clap
  dependency-version: 4.6.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: uuid
  dependency-version: 1.27.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
- dependency-name: encoding_rs
  dependency-version: 0.8.42
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-07 12:14:45 +00:00
dependabot[bot]andGitHub 7300124445 chore(deps): bump the github-actions group with 5 updates
Bumps the github-actions group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [github/codeql-action/init](https://github.com/github/codeql-action) | `4.38.0` | `4.38.1` |
| [github/codeql-action/autobuild](https://github.com/github/codeql-action) | `4.38.0` | `4.38.1` |
| [github/codeql-action/analyze](https://github.com/github/codeql-action) | `4.38.0` | `4.38.1` |
| [dtolnay/rust-toolchain](https://github.com/dtolnay/rust-toolchain) | `6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772` | `02cb101ec7c40f2c49e1d9714d64511d8e1b74de` |
| [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) | `4.38.0` | `4.38.1` |


Updates `github/codeql-action/init` from 4.38.0 to 4.38.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/b96794f015dfd88f77b49b1c93e0fa7110f94c63...1c5b675653bb5c22dbe9b12b556ec555138e09fd)

Updates `github/codeql-action/autobuild` from 4.38.0 to 4.38.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/b96794f015dfd88f77b49b1c93e0fa7110f94c63...1c5b675653bb5c22dbe9b12b556ec555138e09fd)

Updates `github/codeql-action/analyze` from 4.38.0 to 4.38.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/b96794f015dfd88f77b49b1c93e0fa7110f94c63...1c5b675653bb5c22dbe9b12b556ec555138e09fd)

Updates `dtolnay/rust-toolchain` from 6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 to 02cb101ec7c40f2c49e1d9714d64511d8e1b74de
- [Release notes](https://github.com/dtolnay/rust-toolchain/releases)
- [Commits](https://github.com/dtolnay/rust-toolchain/compare/6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772...02cb101ec7c40f2c49e1d9714d64511d8e1b74de)

Updates `github/codeql-action/upload-sarif` from 4.38.0 to 4.38.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/b96794f015dfd88f77b49b1c93e0fa7110f94c63...1c5b675653bb5c22dbe9b12b556ec555138e09fd)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.38.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.38.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.38.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: dtolnay/rust-toolchain
  dependency-version: 02cb101ec7c40f2c49e1d9714d64511d8e1b74de
  dependency-type: direct:production
  dependency-group: github-actions
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.38.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-23 12:19:42 +00:00
DevidandGitHub 62987f035c Merge pull request #13 from masdevid/dependabot/cargo/minor-and-patch-78de0ddba4
chore(deps): bump the minor-and-patch group with 2 updates
2026-09-18 04:17:37 +07:00
DevidandGitHub 5420713bbb Merge branch 'master' into dependabot/cargo/minor-and-patch-78de0ddba4 2026-09-18 04:16:21 +07:00
DevidandGitHub 5eab5feccb Merge pull request #14 from masdevid/dependabot/github_actions/github-actions-6b15e67bac
chore(deps): bump the github-actions group with 4 updates
2026-09-18 04:15:43 +07:00
dependabot[bot]andGitHub fdbaeb68a5 chore(deps): bump the github-actions group with 4 updates
Bumps the github-actions group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63)

Updates `github/codeql-action/autobuild` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63)

Updates `github/codeql-action/analyze` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63)

Updates `github/codeql-action/upload-sarif` from 4.37.9 to 4.38.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/cdf488f595d80d6e07e03d4674febd5ab45fa938...b96794f015dfd88f77b49b1c93e0fa7110f94c63)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-16 12:18:41 +00:00
dependabot[bot]andGitHub be41b43703 chore(deps): bump the minor-and-patch group with 2 updates
Bumps the minor-and-patch group with 2 updates: [uuid](https://github.com/uuid-rs/uuid) and [encoding_rs](https://github.com/hsivonen/encoding_rs).


Updates `uuid` from 1.26.0 to 1.26.1
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.26.0...v1.26.1)

Updates `encoding_rs` from 0.8.35 to 0.8.41
- [Commits](https://github.com/hsivonen/encoding_rs/compare/v0.8.35...v0.8.41)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 1.26.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
- dependency-name: encoding_rs
  dependency-version: 0.8.41
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-16 12:14:11 +00:00
DevidandGitHub 186b846936 Merge pull request #12 from masdevid/dependabot/cargo/dirs-7.0.0
chore(deps): bump dirs from 6.0.0 to 7.0.0
2026-09-10 03:06:34 +07:00
DevidandGitHub b9ad93f873 Merge branch 'master' into dependabot/cargo/dirs-7.0.0 2026-09-10 03:00:31 +07:00
DevidandGitHub 16f10805f3 Merge pull request #11 from masdevid/dependabot/cargo/minor-and-patch-8d2c85db1c
chore(deps): bump uuid from 1.25.0 to 1.26.0 in the minor-and-patch group
2026-09-10 03:00:14 +07:00
dependabot[bot]andGitHub 2ee8a72fe0 chore(deps): bump dirs from 6.0.0 to 7.0.0
Bumps dirs from 6.0.0 to 7.0.0.

---
updated-dependencies:
- dependency-name: dirs
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-09 12:14:45 +00:00
dependabot[bot]andGitHub 868752d39f chore(deps): bump uuid in the minor-and-patch group
Bumps the minor-and-patch group with 1 update: [uuid](https://github.com/uuid-rs/uuid).


Updates `uuid` from 1.25.0 to 1.26.0
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/1.25.0...v1.26.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 1.26.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-09 12:14:42 +00:00
DevidandGitHub cc464e85ad Merge pull request #10 from masdevid/dependabot/github_actions/github-actions-7c7a268a88
chore(deps): bump the github-actions group with 5 updates
2026-09-02 19:33:44 +07:00
DevidandGitHub f87735538b Merge pull request #9 from masdevid/dependabot/cargo/minor-and-patch-0d901d6848
chore(deps): bump uuid from 1.24.1 to 1.25.0 in the minor-and-patch group
2026-09-02 19:33:39 +07:00
dependabot[bot]andGitHub af7715621d chore(deps): bump the github-actions group with 5 updates
Bumps the github-actions group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [github/codeql-action/init](https://github.com/github/codeql-action) | `4.37.8` | `4.37.9` |
| [github/codeql-action/autobuild](https://github.com/github/codeql-action) | `4.37.8` | `4.37.9` |
| [github/codeql-action/analyze](https://github.com/github/codeql-action) | `4.37.8` | `4.37.9` |
| [softprops/action-gh-release](https://github.com/softprops/action-gh-release) | `3.0.2` | `3.0.3` |
| [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) | `4.37.8` | `4.37.9` |


Updates `github/codeql-action/init` from 4.37.8 to 4.37.9
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28...cdf488f595d80d6e07e03d4674febd5ab45fa938)

Updates `github/codeql-action/autobuild` from 4.37.8 to 4.37.9
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28...cdf488f595d80d6e07e03d4674febd5ab45fa938)

Updates `github/codeql-action/analyze` from 4.37.8 to 4.37.9
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28...cdf488f595d80d6e07e03d4674febd5ab45fa938)

Updates `softprops/action-gh-release` from 3.0.2 to 3.0.3
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/3d0d9888cb7fd7b750713d6e236d1fcb99157228...efb35369e0ad2afab669f228072c1b0d510eae64)

Updates `github/codeql-action/upload-sarif` from 4.37.8 to 4.37.9
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28...cdf488f595d80d6e07e03d4674febd5ab45fa938)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.37.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-02 12:19:43 +00:00
dependabot[bot]andGitHub 6647b189ec chore(deps): bump uuid in the minor-and-patch group
Bumps the minor-and-patch group with 1 update: [uuid](https://github.com/uuid-rs/uuid).


Updates `uuid` from 1.24.1 to 1.25.0
- [Release notes](https://github.com/uuid-rs/uuid/releases)
- [Commits](https://github.com/uuid-rs/uuid/compare/v1.24.1...1.25.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 1.25.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-26 12:15:19 +00:00
Devid HW 7eace36bb6 refactor: extract CII helper into standalone masdevid/cii-best-practices skill
scripts/cii_criteria.py and scripts/cii_justifications.json moved to the
new dedicated repo, generalized for any project:

  https://github.com/masdevid/cii-best-practices

Install as an agent skill with:
  npx skills add masdevid/cii-best-practices
2026-08-26 06:28:49 +07:00
Devid HW 302a0c5624 fix(ci): move GPG signing guard out of step if: — secrets context invalid there
Referencing secrets.* in a step-level if: expression makes GitHub reject
the whole workflow file at parse time: every push to any branch produced
a startup-failure run for release.yml with zero jobs ('Code Scanning
could not...' style runs named .github/workflows/release.yml). The tags
trigger was irrelevant because an unparseable workflow has no readable
triggers.

Fix: evaluate the both-secrets-present check in job-level env (where the
secrets context IS allowed) and test env.HAS_GPG_SECRETS in the step if:.
Behavior unchanged: sign when both secrets exist, ship unsigned otherwise.
2026-08-26 05:14:50 +07:00
Devid HW 608b07cead fix(ci): satisfy rustfmt and clippy after bin+lib split
The Rust workflow lint job failed on master:
- cargo fmt --check: imports in src/main.rs were misordered
  (mcp_server/models/pipeline lines out of alphabetical order,
  McpError/McpRequest/McpResponse tuple unsorted) from b843146.
- cargo clippy -D warnings: clippy::new_without_default now fires on
  DealAnalyzer, ReportExtractor, OptimizationParser, StageExecutor
  and McpServer because the lib target (src/lib.rs) makes their
  pub constructors part of the public API.

Fix: reorder main.rs imports per rustfmt; add Default impls
delegating to new() for the five types.
2026-08-26 05:02:44 +07:00
Devid HW 6db5460b99 docs: add required URLs to legacy CII justifications (report_archive, vulnerability_report_process, contribution_requirements) 2026-08-26 04:51:29 +07:00
Devid HW fcf7ac26dc fix: use correct OSPS form-field names in CII edit URLs 2026-08-26 04:26:46 +07:00
Devid HW 09b4fbd831 feat: support OSPS Baseline schema in CII criteria script 2026-08-26 03:40:16 +07:00
Devid HW 3cbb5b00a7 ci: enable manual workflow_dispatch for Scorecard rescan 2026-08-26 03:28:40 +07:00
Devid HW 65b0346628 feat: auto-open generated bestpractices.dev URL in browser when run interactively 2026-08-26 03:26:38 +07:00
Devid HW c65c4b5d1c docs: add SECURITY.md and GPG release signing for OpenSSF passing badge
Satisfies vulnerability_report_process/know_secure_design/know_common_errors via SECURITY.md; delivery_unsigned via GPG-signed releases (public key in docs/signing-key.asc); N/A justifications for the 4 N/A-able MUST criteria (crypto_password_storage, vulnerability_report_private, vulnerability_report_response, release_notes_vulns). Backs the OpenSSF Best Practices passing badge and closes the CIIBestPracticesID alert.
2026-08-26 03:17:38 +07:00
Devid HW b843146554 test: add cargo-fuzz fuzzing harness
adds lib target + cargo-fuzz fuzz targets exercising pure parsers; backs dynamic_analysis criteria and the Scorecard fuzzing check.
2026-08-26 02:58:06 +07:00
Devid HW d8b0b37919 docs: add CONTRIBUTING.md and CII best-practices criteria helper
The scripts/cii_criteria.py helper fetches bestpractices.dev criteria
and generates pre-filled edit URLs for each criterion, streamlining
badge maintenance. CONTRIBUTING.md backs the contribution and testing
criteria referenced by the CII best-practices submission.
2026-08-26 02:38:16 +07:00
Devid HW 38d897d52f ci: trigger scorecard rescan after adding strict-status ruleset 2026-08-25 15:43:29 +07:00
Devid HW e3b04f51b6 ci: rescan scorecard after strict branch-protection settled 2026-08-25 12:00:14 +07:00
Devid HW 66f728d545 ci: trigger scorecard rescan for tightened branch-protection 2026-08-25 11:56:33 +07:00
Devid HW 06a4f8b87d ci: trigger scorecard rescan for branch-protection update 2026-08-25 11:35:51 +07:00
Devid HW ac50ae7bae ci: declare explicit least-privilege permissions (fix Token-Permissions) 2026-08-25 10:44:44 +07:00
Devid HW dece88c514 ci: trigger OpenSSF Scorecard workflow 2026-08-25 10:39:16 +07:00
Devid HW 2951f372e3 ci: enable CodeQL + add code-scanning badge 2026-08-25 10:36:18 +07:00
Devid HW 3c6da1d1d2 ci(scorecard): auto-publish badge.json to badges branch 2026-08-25 10:36:05 +07:00
Devid HW 64cdc30df7 docs(readme): use static scorecard badge (shields ossf backend broken upstream) 2026-08-25 10:30:22 +07:00
Devid HW 5c4bb2a863 docs(readme): activate CII Best Practices badge (id 14227) 2026-08-25 10:23:27 +07:00
Devid HW 5c2b4c52a0 docs(readme): add CII Best Practices badge (placeholder until enrollment) 2026-08-25 10:09:40 +07:00
Devid HW e2cdd0684b ci: pin mcp-publisher download 2026-08-25 09:50:08 +07:00
Devid HW 8a56394f1c ci(release): support RELEASE_PAT for approval-free bot PRs (falls back to GITHUB_TOKEN) 2026-08-25 09:32:18 +07:00
Devid HW 845fce7d68 docs: add documentation index and README navigation 2026-08-25 09:25:30 +07:00
Devid HW 019ddf7c21 docs(readme): copyable install instructions for major LLM clients 2026-08-25 09:23:53 +07:00
Devid HW 599dcb14ba fix(release): attest final release artifacts instead of pre-repackage builds 2026-08-25 09:13:43 +07:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
89d7ff5186 ci: update server.json SHA256 for v1.34.3 (#8)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-25 02:03:12 +00:00
25 changed files with 1984 additions and 190 deletions
+35
View File
@@ -0,0 +1,35 @@
name: CodeQL
on:
push:
branches: [master]
pull_request:
branches: [master]
schedule:
- cron: '22 4 * * 1'
workflow_dispatch:
permissions:
contents: read
jobs:
analyze:
name: Analyze (Rust)
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Initialize CodeQL
uses: github/codeql-action/init@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4
with:
languages: rust
- name: Autobuild
uses: github/codeql-action/autobuild@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4
+1
View File
@@ -4,6 +4,7 @@ on: [pull_request]
permissions:
contents: read
pull-requests: read
jobs:
dependency-review:
+141 -73
View File
@@ -23,15 +23,11 @@ jobs:
build-macos:
runs-on: macos-latest
permissions:
contents: read
id-token: write # Required for build provenance attestation (OIDC)
attestations: write # Required to publish the attestation
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Rust
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # v1
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # v1
with:
toolchain: stable
@@ -64,22 +60,13 @@ jobs:
name: macos-binary
path: dist/mcp-mt5-quant-macos-arm64.tar.gz
- name: Generate build provenance attestation
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-path: dist/mcp-mt5-quant-macos-arm64.tar.gz
build-linux:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Required for build provenance attestation (OIDC)
attestations: write # Required to publish the attestation
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Rust
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # v1
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # v1
with:
toolchain: stable
@@ -112,11 +99,6 @@ jobs:
name: linux-binary
path: dist/mcp-mt5-quant-linux-x64.tar.gz
- name: Generate build provenance attestation
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-path: dist/mcp-mt5-quant-linux-x64.tar.gz
# ── Cargo Publish ────────────────────────────────────────────────────────────
cargo-publish:
@@ -128,7 +110,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Rust
uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # v1
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # v1
with:
toolchain: stable
@@ -161,6 +143,11 @@ jobs:
contents: write
env:
RELEASE_TAG: ${{ github.event.inputs.version || github.ref_name }}
# secrets context is NOT available in step-level if: expressions —
# referencing it there makes the whole workflow fail validation
# (startup-failure runs on every push). Route the check through a
# job-level env var instead: env IS readable in if:.
HAS_GPG_SECRETS: ${{ secrets.GPG_PRIVATE_KEY != '' && secrets.GPG_PASSPHRASE != '' }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -176,14 +163,49 @@ jobs:
name: linux-binary
path: dist
# ── GPG signing of release artifacts (delivery_unsigned) ────────────────
# Guarded: only runs when BOTH signing secrets are configured. When they
# are absent the release still ships (unsigned) instead of failing — so
# forks/contributors without the secrets are not blocked. When present,
# each binary gets a detached ASCII-armored signature and the public key
# (docs/signing-key.asc) is attached to the release for verification.
- name: Import GPG key and sign artifacts
if: env.HAS_GPG_SECRETS == 'true'
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
GPG_KEYID: EF1CA6A2E2D0CEFF61DC7F080256A0C36A6D5E72
run: |
echo "$GPG_PRIVATE_KEY" | gpg --batch --import
for f in dist/mcp-mt5-quant-macos-arm64.tar.gz \
dist/mcp-mt5-quant-linux-x64.tar.gz; do
gpg --batch --yes --pinentry-mode loopback \
--passphrase "$GPG_PASSPHRASE" \
--detach-sign --armor -u "$GPG_KEYID" "$f"
done
- name: Build release asset list
id: assets
run: |
{
echo "files<<EOF"
echo "dist/mcp-mt5-quant-macos-arm64.tar.gz"
echo "dist/mcp-mt5-quant-linux-x64.tar.gz"
echo "docs/signing-key.asc"
if [ -f dist/mcp-mt5-quant-macos-arm64.tar.gz.asc ] && \
[ -f dist/mcp-mt5-quant-linux-x64.tar.gz.asc ]; then
echo "dist/mcp-mt5-quant-macos-arm64.tar.gz.asc"
echo "dist/mcp-mt5-quant-linux-x64.tar.gz.asc"
fi
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Create GitHub Release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
with:
tag_name: ${{ env.RELEASE_TAG }}
name: ${{ env.RELEASE_TAG }}
files: |
dist/mcp-mt5-quant-macos-arm64.tar.gz
dist/mcp-mt5-quant-linux-x64.tar.gz
files: ${{ steps.assets.outputs.files }}
draft: false
prerelease: false
generate_release_notes: true
@@ -192,13 +214,17 @@ jobs:
# ── MCP Package ──────────────────────────────────────────────────────────────
# Builds the installable MCP package (binary + config + docs),
# computes its SHA256, and uploads to the release.
# computes its SHA256, and uploads to the release. Also attests the FINAL
# release bytes — the macOS tarball is re-packaged here (server.json added),
# so attesting in the build jobs would cover digests that never ship.
build-mcp-package:
needs: release
runs-on: macos-latest
permissions:
contents: write
contents: write # Attach the package to the GitHub Release
id-token: write # Required for build provenance attestation (OIDC)
attestations: write # Required to publish the attestation
outputs:
sha256: ${{ steps.compute-sha256.outputs.sha256 }}
env:
@@ -212,6 +238,12 @@ jobs:
name: macos-binary
path: dist
- name: Download Linux binary
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: linux-binary
path: dist
- name: Build MCP package
run: |
mkdir -p mcp-package/mcp-server/bin
@@ -223,6 +255,19 @@ jobs:
cp server.json mcp-package/
cd mcp-package && tar -czf ../mcp-mt5-quant-macos-arm64.tar.gz . && cd ..
# Attest the exact bytes attached to the Release: the re-packaged macOS
# tarball at the repo root and the pass-through Linux tarball from the
# artifact — so attested digests match the published assets.
- name: Generate build provenance attestation (macOS)
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-path: mcp-mt5-quant-macos-arm64.tar.gz
- name: Generate build provenance attestation (Linux)
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-path: dist/mcp-mt5-quant-linux-x64.tar.gz
- name: Compute SHA256
id: compute-sha256
run: |
@@ -231,7 +276,7 @@ jobs:
echo "MCP Package SHA256: $SHA256"
- name: Upload MCP package to release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
with:
tag_name: ${{ env.RELEASE_TAG }}
files: mcp-mt5-quant-macos-arm64.tar.gz
@@ -250,6 +295,16 @@ jobs:
# checks, which github-actions[bot] cannot bypass on a direct push. The PR
# runs those checks legitimately, then auto-merges once green. This job
# blocks until the merge lands so mcp-publish reads the patched server.json.
#
# Bot identity (RELEASE_PAT): when the RELEASE_PAT secret exists (a
# fine-grained personal access token owned by masdevid with Contents+PR
# write), the branch push and the PR are attributed to masdevid instead of
# github-actions[bot]. GitHub only holds pull_request workflows for manual
# approval when the PR author is an OUTSIDE contributor — same-owner PRs
# run their checks immediately, making releases fully hands-off. Without
# the secret everything falls back to GITHUB_TOKEN: the release still
# completes, but the server.json PR's required status checks sit in
# "action_required" until manually approved once per release.
update-server-json:
needs: build-mcp-package
@@ -257,6 +312,14 @@ jobs:
permissions:
contents: write # push the ci/* release branch
pull-requests: write # create the PR and enable auto-merge
env:
# Single bot identity used for BOTH the git push and the gh pr calls —
# GitHub ties workflow-trigger approval to the PR-authoring identity,
# so push and PR must match. Resolves to RELEASE_PAT when configured,
# otherwise the default GITHUB_TOKEN, so nothing breaks before the
# secret is added. Declared here instead of interpolated inline so the
# token never lands on a command line; GitHub masks it in logs anyway.
RELEASE_PAT_OR_TOKEN: ${{ secrets.RELEASE_PAT || github.token }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
@@ -302,6 +365,13 @@ jobs:
id: commit
run: |
BRANCH="ci/server-json-sha-${VERSION}"
# Authenticate ALL pushes (stale-branch cleanup + branch upload)
# with the SAME identity that creates the PR below: GitHub ties
# workflow-trigger approval to the PR author, so a mismatch here
# would defeat the RELEASE_PAT hands-off path. Token comes from the
# job-level env (never interpolated inline, never echoed).
git remote set-url --push origin \
"https://x-access-token:${RELEASE_PAT_OR_TOKEN}@github.com/masdevid/mt5-quant.git"
# Drop any stale branch/PR left over from a previous attempt at
# this release so every run starts from a clean slate
git push origin --delete "$BRANCH" 2>/dev/null || true
@@ -334,20 +404,20 @@ jobs:
# Same rule as above: no CI-skip marker in the title — GitHub
# honors markers on PR titles too, which would suppress the
# required checks.
GH_TOKEN="${{ github.token }}" gh pr create \
GH_TOKEN="$RELEASE_PAT_OR_TOKEN" gh pr create \
--title "ci: update server.json SHA256 for v${VERSION}" \
--body "Automated MCP package hash update." \
--base master \
--head "$BRANCH"
GH_TOKEN="${{ github.token }}" gh pr merge "$BRANCH" --auto --squash
GH_TOKEN="$RELEASE_PAT_OR_TOKEN" gh pr merge "$BRANCH" --auto --squash
# Block until required checks (build, lint, cargo-deny x4) finish
# and auto-merge completes — mcp-publish depends on this job and
# checks out master expecting the patched server.json
DEADLINE=$((SECONDS + 1800))
while (( SECONDS < DEADLINE )); do
STATE=$(GH_TOKEN="${{ github.token }}" gh pr view "$BRANCH" --json state --jq .state)
STATE=$(GH_TOKEN="$RELEASE_PAT_OR_TOKEN" gh pr view "$BRANCH" --json state --jq .state)
case "$STATE" in
MERGED)
echo "server.json PR merged to master"
@@ -384,53 +454,51 @@ jobs:
- name: Install mcp-publisher
id: install-publisher
env:
# Hash-pinned download (OpenSSF Scorecard Pinned-Dependencies):
# PUB_SHA256 is the mcp-publisher_linux_amd64.tar.gz entry from
# registry_1.8.1_checksums.txt shipped in the same release.
# Bump both values together when upgrading.
PUB_VERSION: v1.8.1
PUB_SHA256: a06c9096dcb9727c13555b6be26c7effa707b01f06a4c561ba7a3635443cf2cc
run: |
# Fetch the download URL for linux_amd64 directly from the release assets API
# (asset name format changed in v1.6.0 — look it up rather than constructing it)
URL=$(curl -sf \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/modelcontextprotocol/registry/releases/latest" \
| python3 -c "
import sys, json
r = json.load(sys.stdin)
tag = r['tag_name']
assets = r.get('assets', [])
match = next((a['browser_download_url'] for a in assets
if 'linux' in a['name'] and 'amd64' in a['name']
and a['name'].endswith('.tar.gz')
and 'sbom' not in a['name']
and 'sigstore' not in a['name']), None)
if match:
print(match)
else:
print(f'https://github.com/modelcontextprotocol/registry/releases/download/{tag}/mcp-publisher_linux_amd64.tar.gz', file=sys.stderr)
sys.exit(1)
" 2>/dev/null)
URL="https://github.com/modelcontextprotocol/registry/releases/download/${PUB_VERSION}/mcp-publisher_linux_amd64.tar.gz"
if [[ -z "$URL" ]]; then
echo "Downloading: $URL"
if ! curl -fsSL -o "$RUNNER_TEMP/mcp-publisher.tar.gz" "$URL"; then
echo "installed=false" >> "$GITHUB_OUTPUT"
echo "Could not resolve mcp-publisher download URL"
else
echo "Downloading: $URL"
if curl -fsSL -o mcp-publisher.tar.gz "$URL"; then
tar -xzf mcp-publisher.tar.gz 2>/dev/null || true
BINARY=$(find . -maxdepth 3 -name "mcp-publisher" ! -path "./.git/*" | head -1)
if [[ -n "$BINARY" && -f "$BINARY" ]]; then
chmod +x "$BINARY"
sudo mv "$BINARY" /usr/local/bin/mcp-publisher
echo "installed=true" >> "$GITHUB_OUTPUT"
echo "Installed: $(mcp-publisher --version 2>/dev/null || echo 'ok')"
else
echo "installed=false" >> "$GITHUB_OUTPUT"
echo "Binary not found in archive"
fi
rm -f mcp-publisher.tar.gz
else
echo "installed=false" >> "$GITHUB_OUTPUT"
echo "Download failed: $URL"
fi
echo "Download failed: $URL"
exit 0
fi
# Never execute unverified bytes: hard-fail the job on any digest
# mismatch (upstream re-release or tampering)
ACTUAL=$(sha256sum "$RUNNER_TEMP/mcp-publisher.tar.gz" | awk '{print $1}')
if [[ "$ACTUAL" != "$PUB_SHA256" ]]; then
echo "::error::SHA256 mismatch for mcp-publisher ${PUB_VERSION}: expected ${PUB_SHA256}, got ${ACTUAL}"
exit 1
fi
echo "SHA256 verified: $ACTUAL"
EXTRACT_DIR="$(mktemp -d)"
if ! tar -xzf "$RUNNER_TEMP/mcp-publisher.tar.gz" -C "$EXTRACT_DIR"; then
rm -rf "$EXTRACT_DIR" "$RUNNER_TEMP/mcp-publisher.tar.gz"
echo "installed=false" >> "$GITHUB_OUTPUT"
echo "Extraction failed"
exit 0
fi
if [[ -f "$EXTRACT_DIR/mcp-publisher" ]]; then
chmod +x "$EXTRACT_DIR/mcp-publisher"
sudo mv "$EXTRACT_DIR/mcp-publisher" /usr/local/bin/mcp-publisher
echo "installed=true" >> "$GITHUB_OUTPUT"
echo "Installed: $(mcp-publisher --version 2>/dev/null || echo 'ok')"
else
echo "installed=false" >> "$GITHUB_OUTPUT"
echo "Binary not found in archive"
fi
rm -rf "$EXTRACT_DIR" "$RUNNER_TEMP/mcp-publisher.tar.gz"
- name: Validate server.json before publish
id: validate
run: |
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # v1
- uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # v1
with:
toolchain: stable
components: clippy, rustfmt
+46 -3
View File
@@ -1,12 +1,14 @@
name: Scorecard supply-chain security
on:
branch_protection_rule:
workflow_dispatch:
schedule:
- cron: '30 6 * * 3'
push:
branches: [master]
permissions: read-all
permissions:
contents: read
jobs:
analysis:
@@ -15,7 +17,7 @@ jobs:
permissions:
security-events: write
id-token: write
contents: read
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -33,6 +35,47 @@ jobs:
name: SARIF file
path: results.sarif
- uses: github/codeql-action/upload-sarif@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4
- uses: github/codeql-action/upload-sarif@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4
with:
sarif_file: results.sarif
- name: Update badge JSON
if: github.ref == 'refs/heads/master'
run: |
set -euo pipefail
python3 - <<'PY'
import json
import urllib.request
url = "https://api.scorecard.dev/projects/github.com/masdevid/mt5-quant"
with urllib.request.urlopen(url) as resp:
data = json.load(resp)
score = float(data["score"])
if score >= 9:
color = "brightgreen"
elif score >= 7:
color = "yellowgreen"
elif score >= 5:
color = "yellow"
else:
color = "red"
badge = {
"schemaVersion": 1,
"label": "OpenSSF Scorecard",
"message": f"{score:g}",
"color": color,
}
with open("badge.json", "w") as f:
json.dump(badge, f)
print("Wrote badge.json:", badge)
PY
git remote set-url origin "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
git checkout -B badges
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -f badge.json
git commit -m "chore: update OpenSSF Scorecard badge" || echo "no changes to commit"
git push -f origin badges
+40
View File
@@ -0,0 +1,40 @@
# Contributing to MT5-Quant
Thanks for your interest in improving MT5-Quant! This document explains how to
contribute and what we expect from contributions.
## How to contribute
1. **Fork** the repository and create a topic branch from `master`.
2. Make your change, keeping it focused (one logical change per PR).
3. Open a **pull request against `master`**. A pull request template
(`.github/PULL_REQUEST_TEMPLATE.md`) is provided — please fill it in.
4. Ensure CI passes (build, `cargo test`, clippy, formatting, cargo-deny,
CodeQL). Maintainers review and merge once checks and review are satisfied.
## Development setup
- Install Rust (stable toolchain) and, for full backtests, Wine/MT5 as described
in `README.md` and `docs/QUICKSTART.md`.
- Build the release binary with either:
- `bash scripts/build-rust.sh`, or
- `cargo build --release`
- The binary is produced at `target/release/mt5-quant`.
## Testing requirement
- **Non-trivial changes must include tests.** New functionality should come with
unit or integration tests where practical.
- `cargo test` runs automatically in CI (`rust.yml`) on every push and pull
request, so a change that breaks tests cannot merge.
## Commit style
- Follow **Conventional Commits** (`feat:`, `fix:`, `docs:`, `refactor:`,
`test:`, `release:`), as documented in `AGENTS.md`.
## Issue tracker
- Bugs and enhancement requests are tracked on the project's
[GitHub Issues](https://github.com/masdevid/mt5-quant/issues), with
bug-report and feature-request templates under `.github/ISSUE_TEMPLATE/`.
Generated
+38 -15
View File
@@ -138,9 +138,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.6.6"
version = "4.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca"
checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946"
dependencies = [
"clap_builder",
"clap_derive",
@@ -148,9 +148,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.6.6"
version = "4.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889"
checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d"
dependencies = [
"anstream",
"anstyle",
@@ -160,9 +160,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.6.4"
version = "4.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061"
checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0"
dependencies = [
"heck",
"proc-macro2",
@@ -189,10 +189,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "dirs"
version = "6.0.0"
name = "core_detect"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48"
[[package]]
name = "dirs"
version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f"
dependencies = [
"dirs-sys",
]
@@ -211,11 +217,16 @@ dependencies = [
[[package]]
name = "encoding_rs"
version = "0.8.35"
version = "0.8.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679"
dependencies = [
"cfg-if",
"core_detect",
"multiversion_no_op",
"rustversion",
"scopeguard",
"simdutf8",
]
[[package]]
@@ -500,6 +511,12 @@ dependencies = [
"walkdir",
]
[[package]]
name = "multiversion_no_op"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d"
[[package]]
name = "nu-ansi-term"
version = "0.50.3"
@@ -815,6 +832,12 @@ dependencies = [
"libc",
]
[[package]]
name = "simdutf8"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
[[package]]
name = "smallvec"
version = "1.15.1"
@@ -915,9 +938,9 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.53.1"
version = "1.53.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
checksum = "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044"
dependencies = [
"bytes",
"libc",
@@ -1024,9 +1047,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.24.1"
version = "1.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cefc03fd367c0c6d4305de1b312cf00248c4114f4a0418ce6a6af769e3b0bd9"
checksum = "97277d36b9c3ace13e58fa6e753f8b0bbbf302a18dd193240d70f9e29681059a"
dependencies = [
"getrandom 0.4.2",
"js-sys",
+1 -1
View File
@@ -30,7 +30,7 @@ tracing = "0.1"
tracing-subscriber = "0.3"
uuid = { version = "1.0", features = ["v4"] }
regex = "1.0"
dirs = "6.0"
dirs = "7.0"
walkdir = "2.0"
chrono = { version = "0.4", features = ["serde"] }
encoding_rs = "0.8"
+74 -7
View File
@@ -1,6 +1,6 @@
# MT5-Quant
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/masdevid/mt5-quant/badge)](https://scorecard.dev/viewer/?uri=github.com/masdevid/mt5-quant) [![Rust CI](https://github.com/masdevid/mt5-quant/actions/workflows/rust.yml/badge.svg)](https://github.com/masdevid/mt5-quant/actions/workflows/rust.yml) [![crates.io](https://img.shields.io/crates/v/mt5-quant.svg)](https://crates.io/crates/mt5-quant) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![OpenSSF Scorecard](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/masdevid/mt5-quant/badges/badge.json)](https://scorecard.dev/viewer/?uri=github.com/masdevid/mt5-quant) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/14227/badge)](https://bestpractices.coreinfrastructure.org/projects/14227) [![Rust CI](https://github.com/masdevid/mt5-quant/actions/workflows/rust.yml/badge.svg)](https://github.com/masdevid/mt5-quant/actions/workflows/rust.yml) [![crates.io](https://img.shields.io/crates/v/mt5-quant.svg)](https://crates.io/crates/mt5-quant) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![CodeQL](https://img.shields.io/badge/CodeQL-enabled-brightgreen)](https://github.com/masdevid/mt5-quant/security/code-scanning)
**MCP server for MT5 strategy development on macOS/Linux.** 89 tools to compile, backtest, analyze, optimize, debug crashes, and manage MQL5 Expert Advisors — no Windows required.
@@ -33,14 +33,68 @@ Claude: [compile → clean → backtest → analyze 1,847 deals]
### Install MT5-Quant
Ask your LLM coding platform to install and configure MT5-Quant:
#### Option A — Cargo (recommended, needs Rust toolchain)
> "Please install mt5-quant. It's a Rust-based MCP server for MT5 backtesting at https://github.com/masdevid/mt5-quant. Run its `scripts/setup.sh` to auto-detect Wine and MT5 paths, register the MCP server, and configure everything."
```bash
cargo install mt5-quant --locked
```
The LLM will:
1. Download the pre-built binary (or `cargo build --release`)
2. Run `scripts/setup.sh` to auto-detect Wine/MT5 and write config
3. Register the MCP server with your coding platform
#### Option B — Pre-built binaries (no toolchain)
```bash
# macOS Apple Silicon
curl -LO https://github.com/masdevid/mt5-quant/releases/latest/download/mcp-mt5-quant-macos-arm64.tar.gz
tar xzf mcp-mt5-quant-macos-arm64.tar.gz # → mcp-mt5-quant-macos/mt5-quant
# Linux x64
curl -LO https://github.com/masdevid/mt5-quant/releases/latest/download/mcp-mt5-quant-linux-x64.tar.gz
tar xzf mcp-mt5-quant-linux-x64.tar.gz # → mcp-mt5-quant-linux/mt5-quant
```
Move the binary somewhere on your `PATH` (e.g. `/usr/local/bin` or `~/.local/bin`) so clients can launch it as `mt5-quant`.
#### Option C — Register with your LLM client (copy-paste)
**Claude Code**
```bash
claude mcp add mt5-quant -- mt5-quant --stdio
```
**Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`
```json
{ "mcpServers": { "mt5-quant": { "command": "mt5-quant", "args": ["--stdio"] } } }
```
**Cursor** — `.cursor/mcp.json` (same JSON shape as Claude Desktop)
```json
{ "mcpServers": { "mt5-quant": { "command": "mt5-quant", "args": ["--stdio"] } } }
```
**opencode** — `.opencode/opencode.jsonc`
```jsonc
{ "mcp": { "mt5-quant": { "type": "local", "command": ["mt5-quant", "--stdio"], "enabled": true } } }
```
**Codex CLI** — `~/.codex/config.toml`
```toml
[mcp_servers.mt5-quant]
command = "mt5-quant"
args = ["--stdio"]
```
Then finish setup (auto-detects Wine + MT5 paths):
```bash
bash scripts/setup.sh
```
> **Tip:** you can also just ask your LLM coding agent to do all of the above:
> *"Please install mt5-quant from https://github.com/masdevid/mt5-quant — download or build it, run its `scripts/setup.sh` to auto-detect Wine and MT5 paths, and register it as an MCP server."*
### First Backtest
@@ -228,6 +282,19 @@ For crashes or unexplained failures during backtest/compile/optimization:
**[Full Troubleshooting Guide →](docs/TROUBLESHOOTING.md)**
## Documentation
| Doc | Description |
|-----|-------------|
| [QUICKSTART](docs/QUICKSTART.md) | Step-by-step install, setup, and first backtest |
| [MCP_TOOLS](docs/MCP_TOOLS.md) | Full input/output schemas for all 90 tools |
| [CONFIG](docs/CONFIG.md) | Configuration reference (`config/mt5-quant.yaml`) |
| [ARCHITECTURE](docs/ARCHITECTURE.md) | Design principles and internal module layout |
| [REMOTE_AGENTS](docs/REMOTE_AGENTS.md) | Distribute optimization across Linux agents via Wine |
| [TROUBLESHOOTING](docs/TROUBLESHOOTING.md) | Platform-specific fixes for Wine, MT5, and backtests |
Full index with reading order: [docs/INDEX.md](docs/INDEX.md)
---
## Acknowledgements
+140 -21
View File
@@ -1,35 +1,154 @@
# Security Policy
## Supported Versions
This document describes how to report security issues in **mt5-quant**, and the
secure-development practices the project follows. It backs the OpenSSF Best
Practices criteria `vulnerability_report_process`, `know_secure_design`, and
`know_common_errors`, and the signed-release process described under
[Signing](#signing-of-release-artifacts) backs `delivery_unsigned`.
Only the latest minor release line receives security fixes. Older versions should upgrade.
mt5-quant is a Rust MCP server that drives MetaTrader 5 (under Wine/CrossOver)
to compile, backtest, and analyze trading Expert Advisors. It runs **locally**;
it never exposes a network listener and never transmits user data off the
machine except for the opt-in version self-check (HTTPS to GitHub). The security
notes below focus on the real risks in that model: untrusted input from MT5
report files, the user-supplied Wine/MT5 configuration, and the build/publish
pipeline.
| Version | Supported |
| ------- | ------------------ |
| 1.34.x | :white_check_mark: |
| < 1.34 | :x: |
## Vulnerability reporting process
## Reporting a Vulnerability
We encourage responsible disclosure. If you discover a vulnerability, please
report it through **one** of the following channels (in order of preference):
**Please do not open public GitHub issues for security matters.**
1. **GitHub Security Advisories (recommended).** Open a private security
advisory at <https://github.com/masdevid/mt5-quant/security/advisories/new>.
This keeps the details confidential while we prepare a fix.
2. **Public GitHub Issue.** If you prefer, open a normal issue at
<https://github.com/masdevid/mt5-quant/issues>. Public reports are accepted;
please avoid posting working exploits in the open issue body — link to a
private gist or email the maintainer instead.
Preferred: use GitHub [Private Vulnerability Reporting](https://github.com/masdevid/mt5-quant/security/advisories/new) — **Security tab → Report a vulnerability**. This keeps the report confidential while we work on a fix.
### What to include
Please include as much of the following as you can:
A useful report contains:
- Affected version (and commit SHA, if relevant)
- Steps to reproduce or a proof of concept
- Expected vs. actual behavior
- Any known mitigations
- A clear description of the vulnerability and its impact.
- The affected version(s) (`mt5-quant --version` or the `version` field in
`Cargo.toml`).
- Steps to reproduce, or a proof-of-concept input (e.g. a crafted MT5 report,
`.set` file, or tool argument).
- Any relevant logs, crashes, or sanitizer/fuzzer output.
## Response Commitment
### Expected handling timeline
- **Acknowledgement:** within **72 hours** of your report
- **Fix target:** vulnerabilities rated **critical/high** are targeted for a patch release within **14 days**
- We will keep you informed of progress and credit you in the advisory unless you prefer otherwise
- **Acknowledgement:** within 7 days of a complete report.
- **Triage & severity assessment:** within 14 days.
- **Fix or mitigation plan:** timeline depends on severity; critical issues are
addressed as soon as a patch is ready, and a coordinated disclosure date is
agreed with the reporter when a private advisory is used.
- **Disclosure:** once a fixed release is published, the advisory (if used) is
made public and the fix is credited to the reporter unless they request
anonymity.
## Scope Notes
There is no formal contractual SLA; reports are handled on a best-effort,
case-by-case basis through the public channels above.
MT5-Quant drives Wine and MetaTrader 5 locally — it launches external processes with paths, arguments, and configuration sourced from its YAML config file, `.set` parameter files, and MCP tool arguments. Reports concerning path traversal, config injection, or unsafe command construction through these surfaces are very much in scope and welcome.
## Secure development practices (`know_secure_design`)
Out of scope: vulnerabilities in Wine, MetaTrader 5 itself, or broker infrastructure — please report those upstream to the respective vendors.
mt5-quant follows these practices to keep the code trustworthy:
- **Input validation at every tool boundary.** All 89 MCP tool handlers in
`src/tools/handlers/` parse and validate their arguments at the entry point
(using helpers such as `required_str`, `resolve_report`, and
`prepare_analysis`). Untrusted data — tool arguments, the filesystem, and MT5
output — is never trusted inside core logic.
- **No hardcoded secrets.** The source tree contains no embedded credentials,
API tokens, or private keys. The only secrets are user-provided: a local
`config/mt5-quant.yaml` (gitignored) holding the Wine/MT5 paths, and an
optional release PAT used only in CI. Neither is persisted by the project
itself.
- **Safe parsing of untrusted MT5 reports.** Backtest/optimization reports come
from MetaTrader 5 as either HTML or SpreadsheetML XML (`.htm.xml`, Build 48+).
Parsers in `src/analytics/extract.rs` and `src/optimization/parser.rs` use
explicit, bounded parsing (no `eval`, no regex-backed HTML/script execution)
and fail fast on malformed input. These parsers are additionally exercised by
the cargo-fuzz harness in `fuzz/` (see `dynamic_analysis*` criteria).
- **Least privilege at runtime.** The architecture enforces **a single MT5
instance** and never runs two backtests in parallel on the same Wine prefix.
When no display is available the pipeline falls back to headless/Xvfb mode; the
only external process launched is the user-configured Wine/MT5 binary.
- **Dependency auditing in CI.** Every push and pull request runs
`cargo-deny` (license + advisory + source checks) and the GitHub
`dependency-review` action. Vulnerable or non-compliant dependencies block the
build via the `protect-master` ruleset's required status checks.
- **Fuzzing of parsers.** `fuzz/` contains libFuzzer targets that feed arbitrary
bytes into the report/metrics parsers with debug assertions and integer-
overflow traps enabled, catching panics and invariant violations.
- **Isolation of the Wine/MT5 sandbox.** MT5 runs under the user's Wine prefix,
which is isolated from the host shell environment. The server does not grant
MT5 any elevated privileges.
- **Static analysis.** Clippy runs with `-D warnings` (warnings fail the build)
and GitHub CodeQL (Rust) scans every push/PR.
## Common implementation errors we avoid (`know_common_errors`)
The codebase is deliberately written to avoid well-known Rust/systems pitfalls:
- **Integer overflow.** Rust's release builds disable overflow checks by
default, so arithmetic on deal volumes, prices, and cumulative PnL uses
`checked_*`/`saturating_*` operations or is validated at parse time. The
fuzz harness re-enables `debug-assertions` so overflow traps fire during
testing.
- **Path traversal in `.set` file handling.** `.set` files (UTF-16LE parameter
files for EAs) are read/written through helpers in
`src/tools/handlers/setfiles.rs`. Paths are resolved against the configured
tester profiles directory and normalized; user-supplied filenames are never
interpolated into shell commands and are confined to that directory.
- **UTF-16LE encoding pitfalls.** MetaTrader strips `||Y` flags from UTF-8 `.set`
files, so all writes use UTF-16LE with an explicit BOM and `chmod 444`. The
helpers never assume UTF-8, avoiding silent mojibake / flag loss.
- **Avoiding `unsafe`.** The crate uses no `unsafe` blocks in application logic;
all FFI with Wine/MT5 is performed via the `std::process` API and the system
`curl`/`gpg` binaries, not raw pointer manipulation.
- **Proper error propagation.** Errors are returned as typed `Result`s and
propagated with `?`; there are no swallowed errors or empty `catch`-and-ignore
paths. Invalid states halt fast with descriptive messages (Fail-Fast
philosophy) rather than being silently patched.
- **No injection via shell.** Wine/MT5 is launched with an argument vector (not
a constructed shell string), eliminating command-injection from config values.
## Signing of release artifacts
To satisfy `delivery_unsigned`, **release artifacts are GPG-signed**:
- Each GitHub Release publishes the macOS (`mcp-mt5-quant-macos-arm64.tar.gz`)
and Linux (`mcp-mt5-quant-linux-x64.tar.gz`) binaries **plus** their detached
ASCII-armored signatures (`*.tar.gz.asc`), and the project's public key at
**`docs/signing-key.asc`**.
- The signing key is an RSA-4096 key generated for the `mt5-quant releases`
identity. The public half is committed to the repository; the private half is
held only in CI secrets (`GPG_PRIVATE_KEY`, `GPG_PASSPHRASE`) and is never
committed.
- Signing is performed in CI (`release.yml`) with
`gpg --detach-sign --armor` and is **guarded** so the release still succeeds
if the signing secrets are not configured — it simply omits the signatures in
that case.
### Verifying a downloaded release
```bash
# 1. Import the project public key
gpg --import docs/signing-key.asc
# 2. Verify a release artifact
gpg --verify mcp-mt5-quant-linux-x64.tar.gz.asc \
mcp-mt5-quant-linux-x64.tar.gz
# A good signature from "mt5-quant releases <releases@mt5-quant.local>"
# confirms the artifact was produced by the project's release pipeline.
```
## Supported versions
Security fixes are applied to the latest released version on the `master`
branch. Older releases are not back-ported; users should upgrade to the current
release to receive fixes.
+1
View File
@@ -0,0 +1 @@
{"schemaVersion": 1, "label": "OpenSSF Scorecard", "message": "7.2", "color": "yellowgreen"}
+23
View File
@@ -0,0 +1,23 @@
# Documentation Index
**Start here:** [QUICKSTART.md](QUICKSTART.md) — install MT5-Quant, run `scripts/setup.sh` to auto-detect Wine/MT5 paths, register it with your LLM client, and complete your first backtest.
| Doc | Description |
|-----|-------------|
| [QUICKSTART.md](QUICKSTART.md) | Step-by-step install, setup, and first backtest |
| [MCP_TOOLS.md](MCP_TOOLS.md) | Full input/output schemas for all 90 tools |
| [CONFIG.md](CONFIG.md) | Configuration reference (`config/mt5-quant.yaml`) |
| [ARCHITECTURE.md](ARCHITECTURE.md) | Design principles and internal module layout |
| [REMOTE_AGENTS.md](REMOTE_AGENTS.md) | Distribute optimization across Linux agents via Wine |
| [TROUBLESHOOTING.md](TROUBLESHOOTING.md) | Platform-specific fixes for Wine, MT5, and backtests |
## Suggested reading order
1. [QUICKSTART.md](QUICKSTART.md) — get a working installation and first report
2. [MCP_TOOLS.md](MCP_TOOLS.md) — browse what your LLM agent can call
3. [CONFIG.md](CONFIG.md) — tune symbols, timeframes, deposit defaults
4. [TROUBLESHOOTING.md](TROUBLESHOOTING.md) — when something fails
5. [ARCHITECTURE.md](ARCHITECTURE.md) — how the pipeline works under the hood
6. [REMOTE_AGENTS.md](REMOTE_AGENTS.md) — scale up optimization throughput
These files are also bundled in every release tarball and MCP package, so installed copies stay available offline.
+65
View File
@@ -0,0 +1,65 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
GqF/jfDJVQqPMNY=
=sjIH
-----END PGP PUBLIC KEY BLOCK-----
+4
View File
@@ -0,0 +1,4 @@
target
corpus
artifacts
coverage
+1204
View File
File diff suppressed because it is too large Load Diff
+33
View File
@@ -0,0 +1,33 @@
[package]
name = "mt5-quant-fuzz"
version = "0.0.0"
publish = false
edition = "2021"
[package.metadata]
cargo-fuzz = true
[dependencies]
libfuzzer-sys = "0.4"
[dependencies.mt5-quant]
path = ".."
[[bin]]
name = "parse_metrics"
path = "fuzz_targets/parse_metrics.rs"
test = false
doc = false
bench = false
# Enable debug/overflow assertions during fuzzing. cargo-fuzz builds fuzz
# targets in release mode by default, so we explicitly turn debug-assertions
# back on for the release profile. This backs the
# `dynamic_analysis_enable_assertions` CII criterion: any debug_assert! or
# arithmetic-overflow check inside the crate is active while libFuzzer feeds
# arbitrary input, so crashes from invariant violations are caught as bugs.
[profile.release]
debug-assertions = true
[profile.dev]
debug-assertions = true
+36
View File
@@ -0,0 +1,36 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use mt5_quant::models::Metrics;
// Fuzz target for the pure, I/O-free MT5 backtest report metrics parser.
//
// `Metrics::from_html` takes an arbitrary `&str` and extracts the numeric
// summary metrics from an MT5 HTML/XML report. It is panic-free on bad input:
// every numeric parse uses `unwrap_or`, regex patterns are compile-time
// constants (never panicking), and the function returns `Option<Metrics>`
// (None when no metrics are found). We return early on non-UTF-8 input and on
// the None case, so the fuzzer only ever exercises the parser itself.
fuzz_target!(|data: &[u8]| {
let Ok(text) = std::str::from_utf8(data) else {
// Parser only accepts UTF-8 text; arbitrary byte sequences are
// out of scope and must not cause a crash.
return;
};
if let Some(metrics) = Metrics::from_html(text) {
// Force the computed fields to be materialized so any logic error
// inside the parser surfaces during fuzzing.
let _ = (
metrics.net_profit,
metrics.profit_factor,
metrics.max_dd_pct,
metrics.sharpe_ratio,
metrics.total_trades,
metrics.recovery_factor,
metrics.win_rate_pct,
metrics.gross_profit,
metrics.gross_loss,
);
}
});
+1 -1
View File
@@ -13,7 +13,7 @@
"registryType": "mcpb",
"version": "1.34.3",
"identifier": "https://github.com/masdevid/mt5-quant/releases/download/v1.34.3/mcp-mt5-quant-macos-arm64.tar.gz",
"fileSha256": "TBD_CI_WILL_UPDATE",
"fileSha256": "2f303cb3deb62e47742e5eb4d73a0e3edf200aadf7db9da39a0ef2151d064171",
"transport": {
"type": "stdio"
},
+6
View File
@@ -7,6 +7,12 @@ use crate::models::metrics::Metrics;
pub struct DealAnalyzer;
impl Default for DealAnalyzer {
fn default() -> Self {
Self::new()
}
}
impl DealAnalyzer {
pub fn new() -> Self {
Self
+6
View File
@@ -8,6 +8,12 @@ use crate::models::{Deal, Metrics};
pub struct ReportExtractor;
impl Default for ReportExtractor {
fn default() -> Self {
Self::new()
}
}
impl ReportExtractor {
pub fn new() -> Self {
Self
+60
View File
@@ -0,0 +1,60 @@
pub mod analytics;
pub mod compile;
pub mod models;
pub mod optimization;
pub mod pipeline;
pub mod storage;
pub mod tools;
pub mod mcp_server;
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct McpRequest {
pub jsonrpc: String,
pub id: Option<serde_json::Value>,
pub method: String,
pub params: Option<serde_json::Value>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct McpResponse {
pub jsonrpc: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<McpError>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct McpError {
pub code: i32,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<serde_json::Value>,
}
#[derive(Debug, serde::Serialize)]
pub struct ServerInfo {
pub name: String,
pub version: String,
}
#[derive(Debug, serde::Serialize)]
pub struct InitializeResult {
pub protocol_version: String,
pub capabilities: ServerCapabilities,
pub server_info: ServerInfo,
}
#[derive(Debug, serde::Serialize)]
pub struct ServerCapabilities {
pub experimental: serde_json::Value,
pub tools: ToolCapabilities,
}
#[derive(Debug, serde::Serialize)]
pub struct ToolCapabilities {
pub list_changed: bool,
}
+9 -68
View File
@@ -1,24 +1,16 @@
mod analytics;
mod compile;
mod models;
mod optimization;
mod pipeline;
mod storage;
mod tools;
mod mcp_server;
use anyhow::Result;
use clap::Parser;
use serde_json::{json, Value};
use serde_json::json;
use std::io::{stdout, Write};
use std::time::Instant;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::TcpListener;
use tracing::{error, info};
use crate::models::Config;
use crate::pipeline::backtest::{BacktestParams, BacktestPipeline};
use mt5_quant::mcp_server::{McpServer, Notification};
use mt5_quant::models::Config;
use mt5_quant::pipeline::backtest::{BacktestParams, BacktestPipeline};
use mt5_quant::{McpError, McpRequest, McpResponse};
#[derive(Parser)]
#[command(name = "mt5-quant")]
@@ -45,57 +37,6 @@ struct Cli {
startup_delay: Option<u64>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct McpRequest {
jsonrpc: String,
id: Option<Value>,
method: String,
params: Option<Value>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct McpResponse {
jsonrpc: String,
#[serde(skip_serializing_if = "Option::is_none")]
id: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
result: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
error: Option<McpError>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct McpError {
code: i32,
message: String,
#[serde(skip_serializing_if = "Option::is_none")]
data: Option<Value>,
}
#[derive(Debug, serde::Serialize)]
pub struct ServerInfo {
name: String,
version: String,
}
#[derive(Debug, serde::Serialize)]
pub struct InitializeResult {
protocol_version: String,
capabilities: ServerCapabilities,
server_info: ServerInfo,
}
#[derive(Debug, serde::Serialize)]
pub struct ServerCapabilities {
experimental: Value,
tools: ToolCapabilities,
}
#[derive(Debug, serde::Serialize)]
pub struct ToolCapabilities {
list_changed: bool,
}
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()
@@ -178,9 +119,9 @@ async fn run_test_launch(ea: Option<String>, startup_delay: Option<u64>) -> Resu
async fn run_stdio_server() -> Result<()> {
info!("Starting MT5-Quant MCP server on stdio");
let server = std::sync::Arc::new(mcp_server::McpServer::new());
let server = std::sync::Arc::new(McpServer::new());
let (notification_tx, mut notification_rx) =
tokio::sync::mpsc::unbounded_channel::<mcp_server::Notification>();
tokio::sync::mpsc::unbounded_channel::<Notification>();
server.set_notification_sender(notification_tx).await;
// Spawn notification sender task
@@ -254,7 +195,7 @@ async fn run_tcp_server(port: u16) -> Result<()> {
info!("Starting MT5-Quant MCP server on TCP port {}", port);
let listener = TcpListener::bind(format!("127.0.0.1:{}", port)).await?;
info!("Listening on 127.0.0.1:{}", port);
info!("Running TCP server on port {}", port);
loop {
let (socket, addr) = listener.accept().await?;
@@ -272,7 +213,7 @@ async fn handle_connection(socket: tokio::net::TcpStream) -> Result<()> {
let (reader, mut writer) = socket.into_split();
let mut reader = BufReader::new(reader);
let mut line = String::new();
let server = mcp_server::McpServer::new();
let server = McpServer::new();
loop {
line.clear();
+6
View File
@@ -31,6 +31,12 @@ pub struct McpServer {
notification_tx: Arc<Mutex<Option<mpsc::UnboundedSender<Notification>>>>,
}
impl Default for McpServer {
fn default() -> Self {
Self::new()
}
}
impl McpServer {
pub fn new() -> Self {
let config = ModelsConfig::load().unwrap_or_default();
+6
View File
@@ -17,6 +17,12 @@ pub struct OptimizationPass {
pub struct OptimizationParser;
impl Default for OptimizationParser {
fn default() -> Self {
Self::new()
}
}
impl OptimizationParser {
pub fn new() -> Self {
Self
+7
View File
@@ -40,6 +40,13 @@ impl Stage {
#[allow(dead_code)]
pub struct StageExecutor;
#[allow(dead_code)]
impl Default for StageExecutor {
fn default() -> Self {
Self::new()
}
}
#[allow(dead_code)]
impl StageExecutor {
pub fn new() -> Self {