├── docs ├── .nojekyll ├── _media │ ├── favicon.png │ ├── mcp-discovery.png │ ├── mcp-discovery-logo.png │ ├── example-html-inline.jpg │ ├── mcp-discovery-xpost.png │ └── rust-mcp-stack-icon.png ├── examples │ ├── print_terminal.jpg │ ├── print_terminal_template_file.jpg │ ├── update-md-inline.md │ ├── capabilities.txt │ ├── create-md-plain.md │ ├── update-md-plain.md │ ├── json.txt │ ├── create-md.md │ └── update-md.md ├── example_template │ └── sample_txt_template.txt ├── _sidebar.md ├── _coverpage.md ├── guide │ ├── mcp-discovery-markers.md │ ├── helper-functions.md │ └── command-examples.md ├── README.md ├── index.html └── quickstart.md ├── .gitignore ├── .release-manifest.json ├── rust-toolchain.toml ├── tests ├── fixtures │ ├── template_files │ │ ├── md-template.md │ │ ├── txt-template.txt │ │ └── html-template.html │ ├── md-plain-update-inline.md │ ├── md-plain-update-file-prop.md │ ├── cmds.txt │ ├── txt-create.txt │ ├── md-plain-create.md │ ├── md-plain-update.md │ ├── everything-1.0.0.json │ ├── md-create.md │ ├── md-update.md │ └── md-plain-update-template-prop.md └── common │ └── common.rs ├── src ├── types.rs ├── handler.rs ├── error.rs ├── main.rs ├── utils.rs ├── types │ ├── capabilities.rs │ └── commands.rs ├── std_output.rs └── templates.rs ├── templates ├── common │ └── title.hbs ├── text │ ├── text_prompts.hbs │ ├── text_tools.hbs │ ├── text_resources.hbs │ ├── text_template.txt │ ├── text_resource_templates.hbs │ └── text_summary.hbs ├── markdown │ ├── md_plain_prompts.hbs │ ├── markdown_template.md │ ├── markdown_plain_template.md │ ├── md_plain_resources.hbs │ ├── summary.hbs │ ├── md_plain_tools.hbs │ ├── md_plain_resource_templates.hbs │ ├── md_prompts.hbs │ ├── md_resources.hbs │ ├── md_resource_templates.hbs │ └── md_tools.hbs └── html │ ├── html_prompts.hbs │ ├── html_summary.hbs │ ├── html_resources.hbs │ ├── html_resource_templates.hbs │ ├── html_tools.hbs │ └── html_template.html ├── .github ├── pull_request_template.md └── workflows │ ├── publish.yml │ ├── lint-pr.yml │ ├── ci.yml │ └── release-pr.yml ├── LICENSE ├── dist-workspace.toml ├── Cargo.toml ├── .release-config.json ├── CONTRIBUTING.md ├── Makefile.toml ├── CHANGELOG.md ├── README.md └── wix └── main.wxs /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /.release-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "0.2.2" 3 | } -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.88.0" 3 | components = ["rustfmt", "clippy"] 4 | -------------------------------------------------------------------------------- /tests/fixtures/template_files/md-template.md: -------------------------------------------------------------------------------- 1 | {{> title-version prefix="## " }} 2 | 3 | {{> summary }} 4 | -------------------------------------------------------------------------------- /docs/_media/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-mcp-stack/mcp-discovery/HEAD/docs/_media/favicon.png -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | mod capabilities; 2 | mod commands; 3 | 4 | pub use capabilities::*; 5 | pub use commands::*; 6 | -------------------------------------------------------------------------------- /templates/common/title.hbs: -------------------------------------------------------------------------------- 1 | {{#if prefix}}{{{prefix}}}{{/if}}{{name}} {{version}}{{#if suffix}}{{{suffix}}}{{/if}} -------------------------------------------------------------------------------- /docs/_media/mcp-discovery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-mcp-stack/mcp-discovery/HEAD/docs/_media/mcp-discovery.png -------------------------------------------------------------------------------- /tests/fixtures/template_files/txt-template.txt: -------------------------------------------------------------------------------- 1 | {{> title-version prefix="## " }} 2 | 3 | Summary: 4 | {{> summary }} 5 | -------------------------------------------------------------------------------- /docs/examples/print_terminal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-mcp-stack/mcp-discovery/HEAD/docs/examples/print_terminal.jpg -------------------------------------------------------------------------------- /docs/_media/mcp-discovery-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-mcp-stack/mcp-discovery/HEAD/docs/_media/mcp-discovery-logo.png -------------------------------------------------------------------------------- /docs/_media/example-html-inline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-mcp-stack/mcp-discovery/HEAD/docs/_media/example-html-inline.jpg -------------------------------------------------------------------------------- /docs/_media/mcp-discovery-xpost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-mcp-stack/mcp-discovery/HEAD/docs/_media/mcp-discovery-xpost.png -------------------------------------------------------------------------------- /docs/_media/rust-mcp-stack-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-mcp-stack/mcp-discovery/HEAD/docs/_media/rust-mcp-stack-icon.png -------------------------------------------------------------------------------- /docs/examples/print_terminal_template_file.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-mcp-stack/mcp-discovery/HEAD/docs/examples/print_terminal_template_file.jpg -------------------------------------------------------------------------------- /tests/fixtures/template_files/html-template.html: -------------------------------------------------------------------------------- 1 | 2 | {{> title-version prefix="

" suffix="

" }} 3 | 4 | Summary: 5 | 6 | {{> summary }} 7 | -------------------------------------------------------------------------------- /docs/example_template/sample_txt_template.txt: -------------------------------------------------------------------------------- 1 | Server Information: 2 | 3 | Server Name: {{name}} 4 | Server Version: {{version}} 5 | 6 | Summary: 7 | 8 | {{> txt-summary }} -------------------------------------------------------------------------------- /templates/text/text_prompts.hbs: -------------------------------------------------------------------------------- 1 | {{#if prompts}} 2 | {{{capability_title "📝 Prompts " (len prompts) true}}} 3 | 4 | {{#each prompts}} 5 | {{plus_one @index}}. {{{this.name}}} : {{{this.description}}} 6 | 7 | {{/each}} 8 | {{/if}} 9 | -------------------------------------------------------------------------------- /templates/text/text_tools.hbs: -------------------------------------------------------------------------------- 1 | {{#if capabilities.tools}} 2 | {{{capability_title "🛠️ Tools " (len tools) true}}} 3 | 4 | {{#each tools}} 5 | {{plus_one @index}}. {{{this.name}}} : {{{this.description}}} 6 | 7 | {{/each}} 8 | {{/if}} -------------------------------------------------------------------------------- /tests/fixtures/md-plain-update-inline.md: -------------------------------------------------------------------------------- 1 | 2 | 5 | example-servers/everything 1.0.0 6 | -------------------------------------------------------------------------------- /templates/markdown/md_plain_prompts.hbs: -------------------------------------------------------------------------------- 1 | {{#if prompts}} 2 | 3 | ## 📝 Prompts ({{len prompts}}) 4 | 5 | {{#each prompts}} 6 | 7 | - **{{{this.name}}}** 8 | - {{{format_text this.description "
" "['``']"}}} 9 | {{/each}} 10 | {{/if}} -------------------------------------------------------------------------------- /templates/text/text_resources.hbs: -------------------------------------------------------------------------------- 1 | {{#if resources}} 2 | {{{capability_title "📄 Resources " (len resources) true}}} 3 | 4 | {{#each resources}} 5 | {{plus_one @index}}. {{{this.name}}} : {{{this.uri}}} {{#if this.mimeType}}({{{this.mimeType}}}){{/if}} 6 | 7 | {{/each}} 8 | {{/if}} 9 | -------------------------------------------------------------------------------- /templates/text/text_template.txt: -------------------------------------------------------------------------------- 1 | {{> title-version }} 2 | 3 | 4 | {{> txt-summary }} 5 | 6 | 7 | 8 | {{> txt-tools }} 9 | 10 | 11 | {{> txt-prompts }} 12 | 13 | 14 | {{> txt-resources }} 15 | 16 | 17 | {{> txt-resource-templates }} 18 | 19 | 20 | ◾ generated by mcp-discovery -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | - Getting started 4 | 5 | - [Quick start](quickstart.md) 6 | - [Update Regions with Markers](guide/mcp-discovery-markers.md) 7 | - [Example Commands](guide/command-examples.md) 8 | - [Helper functions for templates](guide/helper-functions.md) 9 | -------------------------------------------------------------------------------- /templates/markdown/markdown_template.md: -------------------------------------------------------------------------------- 1 | {{> title-version prefix="## " }} 2 | 3 | {{> summary }} 4 | 5 | {{> md-tools }} 6 | 7 | {{> md-prompts }} 8 | 9 | {{> md-resources }} 10 | 11 | {{> md-resource-templates }} 12 | 13 | ◾ generated by [mcp-discovery](https://github.com/rust-mcp-stack/mcp-discovery) 14 | -------------------------------------------------------------------------------- /tests/fixtures/md-plain-update-file-prop.md: -------------------------------------------------------------------------------- 1 | 2 | ## example-servers/everything 1.0.0 3 | | 🟢 Tools (8) | 🟢 Prompts (3) | 🟢 Resources (10) | 🟢 Logging | 🔴 Experimental | 4 | | --- | --- | --- | --- | --- | 5 | -------------------------------------------------------------------------------- /templates/text/text_resource_templates.hbs: -------------------------------------------------------------------------------- 1 | {{#if resource_templates}} 2 | {{{capability_title "🧩 Resource Templates " (len resource_templates) true}}} 3 | 4 | {{#each resource_templates}} 5 | {{plus_one @index}}. {{{this.name}}} : {{{this.uriTemplate}}} {{#if this.mimeType}}({{{this.mimeType}}}){{/if}} 6 | {{{this.description}}} 7 | {{/each}} 8 | {{/if}} -------------------------------------------------------------------------------- /templates/markdown/markdown_plain_template.md: -------------------------------------------------------------------------------- 1 | {{> title-version prefix="## " }} 2 | 3 | {{> summary }} 4 | 5 | {{> md-plain-tools }} 6 | 7 | {{> md-plain-prompts }} 8 | 9 | {{> md-plain-resources }} 10 | 11 | {{> md-plain-resource-templates }} 12 | 13 | ◾ generated by [mcp-discovery](https://github.com/rust-mcp-stack/mcp-discovery) 14 | -------------------------------------------------------------------------------- /templates/text/text_summary.hbs: -------------------------------------------------------------------------------- 1 | {{{capability "Tools" capabilities.tools (len tools)}}} {{{capability "Prompts" capabilities.prompts (len prompts)}}} {{{capability "Resources" capabilities.resources (len resources)}}} {{{capability "Logging" capabilities.logging null}}} {{{capability "Completions" capabilities.completions null}}} {{{capability "Experimental" capabilities.experimental null}}} 2 | -------------------------------------------------------------------------------- /templates/markdown/md_plain_resources.hbs: -------------------------------------------------------------------------------- 1 | {{#if resources}} 2 | ## 📄 Resources ({{len resources}}) 3 | 4 | {{#each resources}} 5 | 6 | - **{{{this.name}}}** 7 | {{#if this.description}} 8 | - {{{format_text this.description "
" "['``']"}}}{{/if}} 9 | {{#if this.uri}} 10 | - URI: {{this.uri}} {{#if this.mimeType}}({{{this.mimeType}}}){{/if}} 11 | {{/if}} 12 | {{/each}} 13 | {{/if}} -------------------------------------------------------------------------------- /templates/markdown/summary.hbs: -------------------------------------------------------------------------------- 1 | | {{{capability_tag "Tools" capabilities.tools (len tools)}}} | {{{capability_tag "Prompts" capabilities.prompts (len prompts)}}} | {{{capability_tag "Resources" capabilities.resources (len resources)}}} | {{{capability_tag "Logging" capabilities.logging null}}} | {{{capability_tag "Completions" capabilities.completions null}}} | {{{capability_tag "Experimental" capabilities.experimental null}}} | 2 | | --- | --- | --- | --- | --- | --- | 3 | -------------------------------------------------------------------------------- /templates/markdown/md_plain_tools.hbs: -------------------------------------------------------------------------------- 1 | {{#if capabilities.tools}} 2 | ## 🛠️ Tools ({{len tools}}) 3 | 4 | {{#each tools}} 5 | 6 | - **{{{this.name}}}** 7 | - {{{format_text this.description "
" "['``']"}}} 8 | {{#if this.params}} 9 | - **Inputs:** 10 | {{#each this.params}} 11 | - {{{this.param_name}}} : {{{tool_param_type 12 | this.param_type}}}
13 | {{/each}} 14 | {{/if}} 15 | {{/each}} 16 | {{/if}} -------------------------------------------------------------------------------- /templates/markdown/md_plain_resource_templates.hbs: -------------------------------------------------------------------------------- 1 | {{#if resource_templates}} 2 | ## 🧩 Resource Templates ({{len resource_templates}}) 3 | 4 | {{#each resource_templates}} 5 | 6 | - **{{{this.name}}}** 7 | {{#if this.description}} 8 | - {{{format_text this.description "
" "['``']"}}} 9 | {{/if}} 10 | {{#if this.uri}} 11 | - URI: {{this.uriTemplate}} {{#if this.mimeType}}({{{this.mimeType}}}){{/if}} 12 | {{/if}} 13 | {{/each}} 14 | {{/if}} -------------------------------------------------------------------------------- /src/handler.rs: -------------------------------------------------------------------------------- 1 | use async_trait::async_trait; 2 | use rust_mcp_sdk::schema::RpcError; 3 | use rust_mcp_sdk::{McpClient, mcp_client::ClientHandler}; 4 | 5 | pub struct MyClientHandler; 6 | 7 | #[async_trait] 8 | impl ClientHandler for MyClientHandler { 9 | async fn handle_process_error( 10 | &self, 11 | error_message: String, 12 | runtime: &dyn McpClient, 13 | ) -> std::result::Result<(), RpcError> { 14 | if !runtime.is_shut_down().await { 15 | eprintln!("{error_message}"); 16 | } 17 | Ok(()) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### 📌 Summary 2 | 3 | 4 | ### 🔍 Related Issues 5 | 6 | 7 | - Fixes # 8 | 9 | 10 | ### ✨ Changes Made 11 | 12 | 13 | - Change 1 14 | - Change 2 15 | - Change 3 16 | 17 | ### 🛠️ Testing Steps 18 | 19 | 20 | ### 💡 Additional Notes 21 | 22 | -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![logo](_media/mcp-discovery.png) 4 | 5 | 6 | 7 | # MCP Discovery (v0.2.2) 8 | 9 | 10 | 11 | > A lightweight CLI tool built in Rust for discovering MCP server capabilities. 12 | 13 | - 🔍 Automated Capability Discovery 14 | - ⚡ Zero-Config, Standalone Binary 15 | - 📦 Adaptable Output Formats 16 | - ⚙️ CI/CD-friendly 17 | 18 | [GitHub](https://github.com/rust-mcp-stack/mcp-discovery) 19 | [Install](https://rust-mcp-stack.github.io/mcp-discovery#quickstart) 20 | [Get Started](#mcp-discovery) 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /templates/markdown/md_prompts.hbs: -------------------------------------------------------------------------------- 1 | {{#if prompts}} 2 | ## 📝 Prompts ({{len prompts}}) 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{#each prompts}} 14 | 15 | 16 | 19 | 20 | 21 | {{/each}} 22 | 23 |
Prompt NameDescription
{{plus_one @index}}. 17 | {{{this.name}}} 18 | {{{format_text this.description "
" "['``']"}}}
24 | {{/if}} 25 | -------------------------------------------------------------------------------- /templates/html/html_prompts.hbs: -------------------------------------------------------------------------------- 1 | {{#if capabilities.prompts}} 2 |

📝 Prompts ({{len prompts}})

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{#each prompts}} 14 | 15 | 16 | 19 | 20 | 21 | {{/each}} 22 | 23 |
Prompt NameDescription
{{plus_one @index}}. 17 | {{{this.name}}} 18 | {{{format_text this.description "
" "['``']"}}}
24 | {{/if}} -------------------------------------------------------------------------------- /templates/markdown/md_resources.hbs: -------------------------------------------------------------------------------- 1 | {{#if resources}} 2 | ## 📄 Resources ({{len resources}}) 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{#each resources}} 15 | 16 | 17 | 20 | 23 | 24 | 25 | {{/each}} 26 | 27 |
Resource NameUriDescription
{{plus_one @index}}. 18 | {{this.name}} 19 | 21 | {{this.uri}} {{#if this.mimeType}}({{{this.mimeType}}}){{/if}} 22 | {{{format_text this.description "
" "['``']"}}}
28 | {{/if}} 29 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to Crates.io 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout Repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Cache Rust 16 | uses: actions/cache@v4 17 | with: 18 | path: | 19 | ~/.rustup/toolchains 20 | ~/.cargo/registry 21 | ~/.cargo/git 22 | target 23 | key: ${{ runner.os }}-rust-${{ steps.toolchain.outputs.cachekey }} 24 | restore-keys: ${{ runner.os }}-rust- 25 | 26 | - name: Install Rust Toolchain 27 | uses: dtolnay/rust-toolchain@stable 28 | 29 | - name: Publish to Crates.io 30 | env: 31 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 32 | run: cargo publish --token $CARGO_REGISTRY_TOKEN 33 | -------------------------------------------------------------------------------- /templates/html/html_summary.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
ToolsPromptsResourcesLoggingCompletionsExperimental
{{{capability_tag "Tools" capabilities.tools (len tools)}}}{{{capability_tag "Prompts" capabilities.prompts (len prompts)}}}{{{capability_tag "Resources" capabilities.resources (len resources)}}}{{{capability_tag "Logging" capabilities.logging null}}}{{{capability_tag "Completions" capabilities.completions null}}}{{{capability_tag "Experimental" capabilities.experimental null}}}
23 | -------------------------------------------------------------------------------- /templates/markdown/md_resource_templates.hbs: -------------------------------------------------------------------------------- 1 | {{#if resource_templates}} 2 | ## 🧩 Resource Templates ({{len resource_templates}}) 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{#each resource_templates}} 15 | 16 | 17 | 20 | 23 | 24 | 25 | {{/each}} 26 | 27 |
NameUri TemplateDescription
{{plus_one @index}}. 18 | {{this.name}} 19 | 21 | {{this.uriTemplate}} {{#if this.mimeType}}({{{this.mimeType}}}){{/if}} 22 | {{{format_text this.description "
" "['``']"}}}
28 | {{/if}} 29 | -------------------------------------------------------------------------------- /templates/html/html_resources.hbs: -------------------------------------------------------------------------------- 1 | {{#if capabilities.resources}} 2 |

📄 Resources ({{len resources}})

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{#each resources}} 15 | 16 | 17 | 20 | 23 | 24 | 25 | {{/each}} 26 | 27 |
Resource NameUriDescription
{{plus_one @index}}. 18 | {{this.name}} 19 | 21 | {{this.uri}} {{#if this.mimeType}}({{{this.mimeType}}}){{/if}} 22 | {{{format_text this.description "
" "['``']"}}}
28 | {{/if}} -------------------------------------------------------------------------------- /templates/html/html_resource_templates.hbs: -------------------------------------------------------------------------------- 1 | {{#if resource_templates}} 2 |

🧩 Resource Templates ({{len resource_templates}})

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{#each resource_templates}} 15 | 16 | 17 | 20 | 23 | 24 | 25 | {{/each}} 26 | 27 |
NameUri TemplateDescription
{{plus_one @index}}. 18 | {{this.name}} 19 | 21 | {{this.uriTemplate}} {{#if this.mimeType}}({{{this.mimeType}}}){{/if}} 22 | {{{format_text this.description "
" "['``']"}}}
28 | {{/if}} -------------------------------------------------------------------------------- /tests/fixtures/cmds.txt: -------------------------------------------------------------------------------- 1 | ./mcp-discovery create -f ../../tests/fixtures/md-create.md -- npx -y @modelcontextprotocol/server-everything 2 | ./mcp-discovery create -f ../../tests/fixtures/md-plain-create.md --template md-plain -- npx -y @modelcontextprotocol/server-everything 3 | ./mcp-discovery create -f ../../tests/fixtures/txt-create.txt --template txt -- npx -y @modelcontextprotocol/server-everything 4 | ./mcp-discovery update -f ../../tests/fixtures/md-update.md -- npx -y @modelcontextprotocol/server-everything 5 | ./mcp-discovery update -f ../../tests/fixtures/md-plain-update.md -t md-plain -- npx -y @modelcontextprotocol/server-everything 6 | ./mcp-discovery update -f ../../tests/fixtures/md-plain-update-file-prop.md -- npx -y @modelcontextprotocol/server-everything 7 | ./mcp-discovery update -f ../../tests/fixtures/md-plain-update-template-prop.md -- npx -y @modelcontextprotocol/server-everything 8 | ./mcp-discovery update -f ../../tests/fixtures/md-plain-update-inline.md -- npx -y @modelcontextprotocol/server-everything -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use rust_mcp_sdk::error::McpSdkError; 2 | use thiserror::Error; 3 | 4 | pub type DiscoveryResult = core::result::Result; 5 | 6 | #[derive(Debug, Error)] 7 | pub enum DiscoveryError { 8 | #[error("The MCP Server failed to initialize successfully.")] 9 | ServerNotInitialized, 10 | #[error("'{0}' is not a valid template!")] 11 | InvalidTemplate(String), 12 | #[error("{0}")] 13 | InvalidSchema(String), 14 | #[error("{0}")] 15 | ParseTemplate(String), 16 | #[error( 17 | "Server details are not available. please ensure the discover() method is called first." 18 | )] 19 | NotDiscovered, 20 | #[error("{0}")] 21 | IoError(#[from] std::io::Error), 22 | #[error("{0}")] 23 | McpSdkError(#[from] McpSdkError), 24 | #[error("{0}")] 25 | SerdeError(#[from] serde_json::Error), 26 | #[error("{0}")] 27 | RenderError(#[from] handlebars::RenderError), 28 | #[error("{0}")] 29 | RegexError(#[from] regex::Error), 30 | } 31 | -------------------------------------------------------------------------------- /.github/workflows/lint-pr.yml: -------------------------------------------------------------------------------- 1 | name: Lint PR 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | - reopened 10 | 11 | permissions: 12 | pull-requests: read 13 | 14 | jobs: 15 | pr-check: 16 | name: Validate PR title 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | - name: Lint PR 22 | uses: amannn/action-semantic-pull-request@v5 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | with: 26 | wip: false # needs write access if enabled 27 | requireScope: false 28 | subjectPattern: ^(?![A-Z]).+$ 29 | subjectPatternError: | 30 | The subject "{subject}" found in the pull request title "{title}" 31 | didn't match the configured pattern. Please ensure that the subject 32 | starts with a lowercase character. 33 | 34 | ci: 35 | name: CI 36 | needs: pr-check 37 | uses: ./.github/workflows/ci.yml 38 | -------------------------------------------------------------------------------- /templates/markdown/md_tools.hbs: -------------------------------------------------------------------------------- 1 | {{#if capabilities.tools}} 2 | ## 🛠️ Tools ({{len tools}}) 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{#each tools}} 15 | 16 | 17 | 20 | 21 | 29 | 30 | {{/each}} 31 | 32 |
Tool NameDescriptionInputs
{{plus_one @index}}. 18 | {{{this.name}}} 19 | {{{format_text this.description "
" "['``']"}}}
22 |
    23 | {{#each this.params}} 24 |
  • {{{this.param_name}}} : {{{tool_param_type 25 | this.param_type}}}
  • 26 | {{/each}} 27 |
28 |
33 | {{/if}} 34 | -------------------------------------------------------------------------------- /tests/common/common.rs: -------------------------------------------------------------------------------- 1 | use mcp_discovery::{McpCapabilities, McpServerInfo}; 2 | use rust_mcp_sdk::macros::JsonSchema; 3 | 4 | pub fn default_mcp_server_info() -> McpServerInfo { 5 | McpServerInfo { 6 | name: Default::default(), 7 | version: Default::default(), 8 | capabilities: McpCapabilities { 9 | tools: false, 10 | prompts: false, 11 | resources: false, 12 | logging: false, 13 | experimental: false, 14 | }, 15 | tools: Default::default(), 16 | prompts: Default::default(), 17 | resources: Default::default(), 18 | resource_templates: Default::default(), 19 | } 20 | } 21 | 22 | #[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug, JsonSchema)] 23 | /// Represents a text replacement operation. 24 | pub struct EditOperation { 25 | /// Text to search for - must match exactly. 26 | #[serde(rename = "oldText")] 27 | pub old_text: String, 28 | #[serde(rename = "newText")] 29 | /// Text to replace the matched text with. 30 | pub new_text: String, 31 | } 32 | -------------------------------------------------------------------------------- /templates/html/html_tools.hbs: -------------------------------------------------------------------------------- 1 | {{#if capabilities.tools}} 2 | 3 |

🛠️ Tools ({{len tools}})

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{#each tools}} 15 | 16 | 17 | 20 | 21 | 29 | 30 | {{/each}} 31 | 32 |
Tool NameDescriptionInputs
{{plus_one @index}}. 18 | {{{this.name}}} 19 | {{{format_text this.description "
" "['``']"}}}
22 |
    23 | {{#each this.params}} 24 |
  • {{{this.param_name}}} : {{{tool_param_type 25 | this.param_type}}}
  • 26 | {{/each}} 27 |
28 |
33 | 34 | {{/if}} 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Rust MCP Stack (mcp-discovery) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, 20 | OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | workflow_call: 7 | 8 | jobs: 9 | rust_check: 10 | name: Rust check 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | - name: Cache Rust 16 | uses: actions/cache@v4 17 | with: 18 | path: | 19 | ~/.rustup/toolchains 20 | ~/.cargo/registry 21 | ~/.cargo/git 22 | target 23 | key: ${{ runner.os }}-rust-${{ steps.toolchain.outputs.cachekey }} 24 | restore-keys: ${{ runner.os }}-rust- 25 | 26 | - name: Install Rust Toolchain 27 | uses: dtolnay/rust-toolchain@master 28 | with: 29 | toolchain: stable 30 | components: rustfmt 31 | 32 | - uses: davidB/rust-cargo-make@v1 33 | - uses: taiki-e/install-action@nextest 34 | 35 | - name: Run cargo make check 36 | run: | 37 | cargo make run-checks 38 | 39 | - name: Spell Check 40 | env: 41 | RUSTDOCFLAGS: "-Dwarnings" 42 | uses: crate-ci/typos@master 43 | 44 | - name: Audit 45 | uses: actions-rust-lang/audit@v1 46 | with: 47 | token: ${{ secrets.GITHUB_TOKEN }} 48 | -------------------------------------------------------------------------------- /docs/examples/update-md-inline.md: -------------------------------------------------------------------------------- 1 | # Server Info and Capabilities 2 | 3 | 4 | 13 | Name: example-servers/everything 14 |
15 | Version: 1.0.0 16 |
17 | Number of tools: 10 18 |

Summary:

19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
ToolsPromptsResourcesLoggingCompletionsExperimental
🟢 Tools (10)🟢 Prompts (3)🟢 Resources (10)🟢 Logging🟢 Completions🔴 Experimental
41 | 42 | 43 | --- 44 | 45 | A Footer -------------------------------------------------------------------------------- /dist-workspace.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["cargo:."] 3 | 4 | # Config for 'dist' 5 | [dist] 6 | # The preferred dist version to use in CI (Cargo.toml SemVer syntax) 7 | cargo-dist-version = "0.30.0" 8 | # CI backends to support 9 | ci = "github" 10 | # The installers to generate for each app 11 | installers = ["shell", "powershell", "npm", "homebrew", "msi"] 12 | # A GitHub repo to push Homebrew formulas to 13 | tap = "rust-mcp-stack/homebrew-tap" 14 | # Target platforms to build apps for (Rust target-triple syntax) 15 | targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"] 16 | # Path that installers should place binaries in 17 | install-path = "~/.rust-mcp-stack/bin" 18 | # Publish jobs to run in CI 19 | publish-jobs = ["homebrew", "npm"] 20 | # Whether to install an updater program 21 | install-updater = false 22 | # Whether dist should create a Github Release or use an existing draft 23 | create-release = false 24 | # A namespace to use when publishing this package to the npm registry 25 | npm-scope = "@rustmcp" 26 | 27 | [dist.github-custom-runners] 28 | global = "ubuntu-22.04" 29 | 30 | [dist.github-custom-runners.x86_64-unknown-linux-gnu] 31 | global = "ubuntu-22.04" 32 | runner = "ubuntu-22.04" 33 | 34 | [dist.github-custom-runners.aarch64-unknown-linux-gnu] 35 | runner = "ubuntu-22.04" 36 | container = { image = "quay.io/pypa/manylinux_2_28_x86_64", host = "x86_64-unknown-linux-musl" } 37 | -------------------------------------------------------------------------------- /.github/workflows/release-pr.yml: -------------------------------------------------------------------------------- 1 | name: ReleasePR 2 | 3 | permissions: 4 | pull-requests: write 5 | contents: write 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | release: 14 | runs-on: ubuntu-latest 15 | outputs: 16 | release_created: ${{ steps.release.outputs.release_created }} 17 | version: ${{ steps.release.outputs.version }} 18 | 19 | permissions: 20 | contents: write 21 | pull-requests: write 22 | 23 | steps: 24 | - name: Checkout Repository 25 | uses: actions/checkout@v4 26 | 27 | - name: Release Please 28 | id: release 29 | uses: googleapis/release-please-action@v4 30 | env: 31 | ACTIONS_STEP_DEBUG: true 32 | with: 33 | token: ${{ secrets.RP_SECRET }} 34 | config-file: .release-config.json 35 | manifest-file: .release-manifest.json 36 | - name: Release Please Output 37 | run: | 38 | echo "release-please output:" 39 | echo "${OUTPUTS}" 40 | env: 41 | OUTPUTS: ${{ toJson(steps.release.outputs) }} 42 | 43 | # docker: 44 | # name: Publish Docker 45 | # needs: release 46 | # if: ${{needs.release.outputs.release_created == 'true'}} 47 | # uses: ./.github/workflows/docker.yml 48 | # with: 49 | # version: ${{needs.release.outputs.version}} 50 | # secrets: 51 | # DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} 52 | # DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} 53 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod cli; 2 | use clap::Parser; 3 | use cli::{CliDiscoveryCommand, CliPrintOptions, CommandArguments}; 4 | use colored::Colorize; 5 | use mcp_discovery::{DiscoveryCommand, LogLevel, McpDiscovery}; 6 | use tracing_subscriber::{self, EnvFilter}; 7 | 8 | #[tokio::main] 9 | async fn main() { 10 | let args = CommandArguments::parse(); 11 | 12 | let command: DiscoveryCommand = args 13 | .command 14 | .unwrap_or(CliDiscoveryCommand::Print(CliPrintOptions { 15 | mcp_server_cmd: args.mcp_server_cmd, 16 | template: args.template, 17 | template_file: args.template_file, 18 | template_string: args.template_string, 19 | log_level: args.log_level, 20 | })) 21 | .into(); 22 | 23 | let filter = format!( 24 | "{}={}", 25 | env!("CARGO_PKG_NAME").to_string().replace("-", "_"), 26 | command.log_level().as_ref().unwrap_or(&LogLevel::info) 27 | ); 28 | 29 | let tracing_filter = EnvFilter::try_new(filter).unwrap_or_else(|_| EnvFilter::new("info")); 30 | 31 | tracing_subscriber::fmt() 32 | .with_env_filter(tracing_filter) 33 | .compact() 34 | .init(); 35 | 36 | let launch_message = format!( 37 | "{} {} ...", 38 | "Launching:".bold(), 39 | &command.mcp_launch_command().join(" "), 40 | ); 41 | 42 | println!("{}", launch_message.bright_green()); 43 | 44 | let mut discovery_agent = McpDiscovery::new(command); 45 | 46 | if let Err(error) = discovery_agent.start().await { 47 | eprintln!("Error: {error}"); 48 | std::process::exit(1); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mcp-discovery" 3 | version = "0.2.2" 4 | authors = ["Ali Hashemi"] 5 | categories = ["command-line-interface", "command-line-utilities"] 6 | description = "A command-line tool written in Rust for discovering and documenting MCP Server capabilities." 7 | repository = "https://github.com/rust-mcp-stack/mcp-discovery" 8 | documentation = "https://docs.rs/mcp-discovery" 9 | keywords = [ 10 | "rust-mcp-stack", 11 | "mcp-discovery", 12 | "mcp-cli", 13 | "rust-mcp-cli", 14 | "rust-mcp-discovery", 15 | ] 16 | homepage = "https://rust-mcp-stack.github.io/mcp-discovery" 17 | license = "MIT" 18 | edition = "2024" 19 | 20 | [lib] 21 | name = "mcp_discovery" 22 | path = "src/lib.rs" 23 | 24 | [package.metadata.wix] 25 | upgrade-guid = "F8C005B2-0006-40E0-93CF-01A2DA37CAB7" 26 | path-guid = "FE1B50BA-4553-470C-8819-8575C25AE238" 27 | license = false 28 | eula = false 29 | 30 | [package.metadata.docs.rs] 31 | all-features = true # Build with all features 32 | 33 | [dependencies] 34 | rust-mcp-sdk = { version = "0.7", default-features = false, features = [ 35 | "client", 36 | "stdio", 37 | "2025_06_18" 38 | ] } 39 | 40 | clap = { version = "4.5", features = ["derive"] } 41 | serde = "1.0" 42 | serde_json = "1.0" 43 | tokio = "1.4" 44 | colored = "3.0" 45 | strip-ansi-escapes = "0.2" 46 | unicode-width = "0.2" 47 | async-trait = "0.1" 48 | thiserror = { version = "2.0" } 49 | handlebars = "6.3" 50 | html-escape = "0.2" 51 | regex = "1.1" 52 | path-clean = "1.0" 53 | tracing = "0.1" 54 | tracing-subscriber = { version = "0.3", features = [ 55 | "env-filter", 56 | "std", 57 | "fmt", 58 | ] } 59 | [dev-dependencies] 60 | tempfile = "3" 61 | 62 | # The profile that 'dist' will build with 63 | [profile.dist] 64 | inherits = "release" 65 | lto = "thin" 66 | -------------------------------------------------------------------------------- /tests/fixtures/txt-create.txt: -------------------------------------------------------------------------------- 1 | example-servers/everything 1.0.0 2 | 3 | 🟢 Tools (8) 🟢 Prompts (3) 🟢 Resources (10) 🟢 Logging 🔴 Experimental 4 | 5 | 6 | 🛠️ Tools (8) 7 | ──────────── 8 | 9 | 1. add : Adds two numbers 10 | 11 | 2. annotatedMessage : Demonstrates how annotations can be used to provide metadata about content 12 | 13 | 3. echo : Echoes back the input 14 | 15 | 4. getResourceReference : Returns a resource reference that can be used by MCP clients 16 | 17 | 5. getTinyImage : Returns the MCP_TINY_IMAGE 18 | 19 | 6. longRunningOperation : Demonstrates a long running operation with progress updates 20 | 21 | 7. printEnv : Prints all environment variables, helpful for debugging MCP server configuration 22 | 23 | 8. sampleLLM : Samples from an LLM using MCP's sampling feature 24 | 25 | 26 | 27 | 📝 Prompts (3) 28 | ────────────── 29 | 30 | 1. simple_prompt : A prompt without arguments 31 | 32 | 2. complex_prompt : A prompt with arguments 33 | 34 | 3. resource_prompt : A prompt that includes an embedded resource reference 35 | 36 | 37 | 38 | 📄 Resources (10) 39 | ───────────────── 40 | 41 | 1. Resource 1 : test://static/resource/1 (text/plain) 42 | 43 | 2. Resource 2 : test://static/resource/2 (application/octet-stream) 44 | 45 | 3. Resource 3 : test://static/resource/3 (text/plain) 46 | 47 | 4. Resource 4 : test://static/resource/4 (application/octet-stream) 48 | 49 | 5. Resource 5 : test://static/resource/5 (text/plain) 50 | 51 | 6. Resource 6 : test://static/resource/6 (application/octet-stream) 52 | 53 | 7. Resource 7 : test://static/resource/7 (text/plain) 54 | 55 | 8. Resource 8 : test://static/resource/8 (application/octet-stream) 56 | 57 | 9. Resource 9 : test://static/resource/9 (text/plain) 58 | 59 | 10. Resource 10 : test://static/resource/10 (application/octet-stream) 60 | 61 | 62 | 63 | 🧩 Resource Templates (1) 64 | ───────────────────────── 65 | 66 | 1. Static Resource : test://static/resource/{id} 67 | A static resource with a numeric ID 68 | 69 | 70 | ◾ generated by mcp-discovery -------------------------------------------------------------------------------- /docs/examples/capabilities.txt: -------------------------------------------------------------------------------- 1 | example-servers/everything 1.0.0 2 | 3 | 🟢 Tools (10) 🟢 Prompts (3) 🟢 Resources (10) 🟢 Logging 🟢 Completions 🔴 Experimental 4 | 5 | 6 | 7 | 🛠️ Tools (10) 8 | ───────────── 9 | 10 | 1. add : Adds two numbers 11 | 12 | 2. annotatedMessage : Demonstrates how annotations can be used to provide metadata about content 13 | 14 | 3. echo : Echoes back the input 15 | 16 | 4. getResourceLinks : Returns multiple resource links that reference different types of resources 17 | 18 | 5. getResourceReference : Returns a resource reference that can be used by MCP clients 19 | 20 | 6. getTinyImage : Returns the MCP_TINY_IMAGE 21 | 22 | 7. longRunningOperation : Demonstrates a long running operation with progress updates 23 | 24 | 8. printEnv : Prints all environment variables, helpful for debugging MCP server configuration 25 | 26 | 9. sampleLLM : Samples from an LLM using MCP's sampling feature 27 | 28 | 10. structuredContent : Returns structured content along with an output schema for client data validation 29 | 30 | 31 | 32 | 📝 Prompts (3) 33 | ────────────── 34 | 35 | 1. simple_prompt : A prompt without arguments 36 | 37 | 2. complex_prompt : A prompt with arguments 38 | 39 | 3. resource_prompt : A prompt that includes an embedded resource reference 40 | 41 | 42 | 43 | 📄 Resources (10) 44 | ───────────────── 45 | 46 | 1. Resource 1 : test://static/resource/1 (text/plain) 47 | 48 | 2. Resource 2 : test://static/resource/2 (application/octet-stream) 49 | 50 | 3. Resource 3 : test://static/resource/3 (text/plain) 51 | 52 | 4. Resource 4 : test://static/resource/4 (application/octet-stream) 53 | 54 | 5. Resource 5 : test://static/resource/5 (text/plain) 55 | 56 | 6. Resource 6 : test://static/resource/6 (application/octet-stream) 57 | 58 | 7. Resource 7 : test://static/resource/7 (text/plain) 59 | 60 | 8. Resource 8 : test://static/resource/8 (application/octet-stream) 61 | 62 | 9. Resource 9 : test://static/resource/9 (text/plain) 63 | 64 | 10. Resource 10 : test://static/resource/10 (application/octet-stream) 65 | 66 | 67 | 68 | 🧩 Resource Templates (1) 69 | ───────────────────────── 70 | 71 | 1. Static Resource : test://static/resource/{id} 72 | A static resource with a numeric ID 73 | 74 | 75 | ◾ generated by mcp-discovery -------------------------------------------------------------------------------- /.release-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", 3 | "release-type": "rust", 4 | "release-as": "", 5 | "include-component-in-tag": false, 6 | "pull-request-title-pattern": "chore: release${component}", 7 | "changelog-sections": [ 8 | { 9 | "type": "feature", 10 | "section": "🚀 Features" 11 | }, 12 | { 13 | "type": "feat", 14 | "section": "🚀 Features" 15 | }, 16 | { 17 | "type": "fix", 18 | "section": "🐛 Bug Fixes" 19 | }, 20 | { 21 | "type": "perf", 22 | "section": "⚡ Performance Improvements" 23 | }, 24 | { 25 | "type": "revert", 26 | "section": "◀️ Reverts" 27 | }, 28 | { 29 | "type": "docs", 30 | "section": "📚 Documentation", 31 | "hidden": false 32 | }, 33 | { 34 | "type": "style", 35 | "section": "🎨 Styles", 36 | "hidden": true 37 | }, 38 | { 39 | "type": "chore", 40 | "section": "⚙️ Miscellaneous Chores", 41 | "hidden": true 42 | }, 43 | { 44 | "type": "refactor", 45 | "section": "🚜 Code Refactoring", 46 | "hidden": true 47 | }, 48 | { 49 | "type": "test", 50 | "section": "🧪 Tests", 51 | "hidden": true 52 | }, 53 | { 54 | "type": "build", 55 | "section": "🛠️ Build System", 56 | "hidden": true 57 | }, 58 | { 59 | "type": "ci", 60 | "section": "🥏 Continuous Integration", 61 | "hidden": true 62 | } 63 | ], 64 | "plugins": [ 65 | "sentence-case" 66 | ], 67 | "pull-request-header": ":robot: Auto-generated release PR", 68 | "packages": { 69 | ".": { 70 | "release-type": "rust", 71 | "draft": false, 72 | "prerelease": false, 73 | "bump-minor-pre-major": true, 74 | "bump-patch-for-minor-pre-major": true, 75 | "include-component-in-tag": false, 76 | "changelogPath": "CHANGELOG.md", 77 | "extra-files": [ 78 | "README.md", 79 | "docs/_coverpage.md", 80 | "docs/quickstart.md", 81 | "docs/README.md" 82 | ] 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # **Contributing to MCP Discovery** 2 | 3 | 🎉 Thank you for your interest in improving **MCP Discovery**! Every contribution, big or small, is valuable and appreciated. 4 | 5 | ## **Code of Conduct** 6 | 7 | We follow the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct). Please be respectful and inclusive when contributing. 8 | 9 | ## **How to Contribute** 10 | 11 | ### Participating in Tests and Documentation 12 | 13 | We highly encourage contributors to improve test coverage and enhance documentation. 14 | 15 | ### Participating in Issues 16 | 17 | You can contribute in three key ways: 18 | 19 | 1. **Report Issues** – If you find a bug or have an idea, open an issue for discussion. 20 | 2. **Help Triage** – Provide details, test cases, or suggestions to clarify issues. 21 | 3. **Resolve Issues** – Investigate problems and submit fixes via Pull Requests (PRs). 22 | 23 | Anyone can participate at any stage, whether it's discussing, triaging, or reviewing PRs. 24 | 25 | ### **Filing a Bug Report** 26 | 27 | When reporting a bug, use the provided issue template and fill in as many details as possible. Don’t worry if you can’t answer everything—just provide what you can. 28 | 29 | ### **Fixing Issues** 30 | 31 | Most issues are resolved through a Pull Request. PRs go through a review process to ensure quality and correctness. 32 | 33 | ## **Pull Requests (PRs)** 34 | 35 | We welcome PRs! Before submitting, please: 36 | 37 | 1. **Discuss major changes** – Open an issue before adding a new feature and opening a PR. 38 | 2. **Create a feature branch** – Fork the repo and branch from `main`. 39 | 3. **Write tests** – If your change affects functionality, add relevant tests. 40 | 4. **Update documentation** – If you modify APIs, update the docs. 41 | 5. **Run checks** – Ensure code consistency, formatting, and pass all validations by running: 42 | 43 | ```sh 44 | cargo make check 45 | ``` 46 | 47 | ### **Commit Best Practices** 48 | 49 | - **Relate PR changes to the issue** – Changes in a pull request (PR) should directly address the specific issue it’s tied to. Unrelated changes should be split into separate issues and PRs to maintain focus and simplify review. 50 | - **Logically separate commits** – Keep changes atomic and easy to review. 51 | - **Maintain a bisect-able history** – Each commit should compile and pass all tests to enable easy debugging with `git bisect` in case of regression. 52 | 53 | ## License 54 | 55 | By contributing to MCP Discovery, you acknowledge and agree that your contributions will be licensed under the terms specified in the LICENSE file located in the root directory of this repository. 56 | 57 | --- 58 | -------------------------------------------------------------------------------- /tests/fixtures/md-plain-create.md: -------------------------------------------------------------------------------- 1 | ## example-servers/everything 1.0.0 2 | | 🟢 Tools (8) | 🟢 Prompts (3) | 🟢 Resources (10) | 🟢 Logging | 🔴 Experimental | 3 | | --- | --- | --- | --- | --- | 4 | ## 🛠️ Tools (8) 5 | 6 | 7 | - **add** 8 | - Adds two numbers 9 | - **Inputs:** 10 | - a : number
11 | - b : number
12 | 13 | - **annotatedMessage** 14 | - Demonstrates how annotations can be used to provide metadata about content 15 | - **Inputs:** 16 | - includeImage : boolean
17 | - messageType : string
18 | 19 | - **echo** 20 | - Echoes back the input 21 | - **Inputs:** 22 | - message : string
23 | 24 | - **getResourceReference** 25 | - Returns a resource reference that can be used by MCP clients 26 | - **Inputs:** 27 | - resourceId : number
28 | 29 | - **getTinyImage** 30 | - Returns the MCP_TINY_IMAGE 31 | 32 | - **longRunningOperation** 33 | - Demonstrates a long running operation with progress updates 34 | - **Inputs:** 35 | - duration : number
36 | - steps : number
37 | 38 | - **printEnv** 39 | - Prints all environment variables, helpful for debugging MCP server configuration 40 | 41 | - **sampleLLM** 42 | - Samples from an LLM using MCP's sampling feature 43 | - **Inputs:** 44 | - maxTokens : number
45 | - prompt : string
46 | 47 | 48 | ## 📝 Prompts (3) 49 | 50 | 51 | - **simple_prompt** 52 | - A prompt without arguments 53 | 54 | - **complex_prompt** 55 | - A prompt with arguments 56 | 57 | - **resource_prompt** 58 | - A prompt that includes an embedded resource reference 59 | 60 | ## 📄 Resources (10) 61 | 62 | 63 | - **Resource 1** 64 | 65 | - URI: test://static/resource/1 (text/plain) 66 | 67 | - **Resource 2** 68 | 69 | - URI: test://static/resource/2 (application/octet-stream) 70 | 71 | - **Resource 3** 72 | 73 | - URI: test://static/resource/3 (text/plain) 74 | 75 | - **Resource 4** 76 | 77 | - URI: test://static/resource/4 (application/octet-stream) 78 | 79 | - **Resource 5** 80 | 81 | - URI: test://static/resource/5 (text/plain) 82 | 83 | - **Resource 6** 84 | 85 | - URI: test://static/resource/6 (application/octet-stream) 86 | 87 | - **Resource 7** 88 | 89 | - URI: test://static/resource/7 (text/plain) 90 | 91 | - **Resource 8** 92 | 93 | - URI: test://static/resource/8 (application/octet-stream) 94 | 95 | - **Resource 9** 96 | 97 | - URI: test://static/resource/9 (text/plain) 98 | 99 | - **Resource 10** 100 | 101 | - URI: test://static/resource/10 (application/octet-stream) 102 | 103 | ## 🧩 Resource Templates (1) 104 | 105 | 106 | - **Static Resource** 107 | - A static resource with a numeric ID 108 | 109 | ◾ generated by [mcp-discovery](https://github.com/rust-mcp-stack/mcp-discovery) 110 | -------------------------------------------------------------------------------- /tests/fixtures/md-plain-update.md: -------------------------------------------------------------------------------- 1 | 2 | ## example-servers/everything 1.0.0 3 | | 🟢 Tools (8) | 🟢 Prompts (3) | 🟢 Resources (10) | 🟢 Logging | 🔴 Experimental | 4 | | --- | --- | --- | --- | --- | 5 | ## 🛠️ Tools (8) 6 | 7 | 8 | - **add** 9 | - Adds two numbers 10 | - **Inputs:** 11 | - a : number
12 | - b : number
13 | 14 | - **annotatedMessage** 15 | - Demonstrates how annotations can be used to provide metadata about content 16 | - **Inputs:** 17 | - includeImage : boolean
18 | - messageType : string
19 | 20 | - **echo** 21 | - Echoes back the input 22 | - **Inputs:** 23 | - message : string
24 | 25 | - **getResourceReference** 26 | - Returns a resource reference that can be used by MCP clients 27 | - **Inputs:** 28 | - resourceId : number
29 | 30 | - **getTinyImage** 31 | - Returns the MCP_TINY_IMAGE 32 | 33 | - **longRunningOperation** 34 | - Demonstrates a long running operation with progress updates 35 | - **Inputs:** 36 | - duration : number
37 | - steps : number
38 | 39 | - **printEnv** 40 | - Prints all environment variables, helpful for debugging MCP server configuration 41 | 42 | - **sampleLLM** 43 | - Samples from an LLM using MCP's sampling feature 44 | - **Inputs:** 45 | - maxTokens : number
46 | - prompt : string
47 | 48 | 49 | ## 📝 Prompts (3) 50 | 51 | 52 | - **simple_prompt** 53 | - A prompt without arguments 54 | 55 | - **complex_prompt** 56 | - A prompt with arguments 57 | 58 | - **resource_prompt** 59 | - A prompt that includes an embedded resource reference 60 | 61 | ## 📄 Resources (10) 62 | 63 | 64 | - **Resource 1** 65 | 66 | - URI: test://static/resource/1 (text/plain) 67 | 68 | - **Resource 2** 69 | 70 | - URI: test://static/resource/2 (application/octet-stream) 71 | 72 | - **Resource 3** 73 | 74 | - URI: test://static/resource/3 (text/plain) 75 | 76 | - **Resource 4** 77 | 78 | - URI: test://static/resource/4 (application/octet-stream) 79 | 80 | - **Resource 5** 81 | 82 | - URI: test://static/resource/5 (text/plain) 83 | 84 | - **Resource 6** 85 | 86 | - URI: test://static/resource/6 (application/octet-stream) 87 | 88 | - **Resource 7** 89 | 90 | - URI: test://static/resource/7 (text/plain) 91 | 92 | - **Resource 8** 93 | 94 | - URI: test://static/resource/8 (application/octet-stream) 95 | 96 | - **Resource 9** 97 | 98 | - URI: test://static/resource/9 (text/plain) 99 | 100 | - **Resource 10** 101 | 102 | - URI: test://static/resource/10 (application/octet-stream) 103 | 104 | ## 🧩 Resource Templates (1) 105 | 106 | 107 | - **Static Resource** 108 | - A static resource with a numeric ID 109 | 110 | ◾ generated by [mcp-discovery](https://github.com/rust-mcp-stack/mcp-discovery) 111 | 112 | -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | 2 | 3 | [tasks.fmt] 4 | install_crate = "rustfmt" 5 | command = "cargo" 6 | args = ["fmt", "--all", "--", "--check"] 7 | 8 | [tasks.clippy] 9 | command = "cargo" 10 | args = ["clippy", "--all-targets", "--", "-D", "warnings"] 11 | 12 | [tasks.test] 13 | install_crate = "nextest" 14 | command = "cargo" 15 | args = ["nextest", "run", "--no-tests=pass"] 16 | 17 | [tasks.run-checks] 18 | dependencies = ["fmt", "clippy", "test"] 19 | 20 | [tasks.clippy-fix] 21 | command = "cargo" 22 | args = ["clippy", "--fix", "--allow-dirty"] 23 | 24 | [tasks.check] 25 | dependencies = ["fmt", "clippy", "test"] 26 | 27 | 28 | 29 | 30 | [tasks.generate-examples] 31 | dependencies = [ 32 | "example-create-md", 33 | "example-create-md-plain", 34 | "example-create-server-info-html", 35 | "example-update-md", 36 | "example-update-md-plain", 37 | "example-update-md-plain", 38 | "example-update-md-inline", 39 | ] 40 | 41 | 42 | [tasks.example-create-md] 43 | command = "cargo" 44 | args = [ 45 | "run", 46 | "--", 47 | "create", 48 | "-t", 49 | "md", 50 | "-f", 51 | "docs/examples/create-md.md", 52 | "--", 53 | "npx", 54 | "-y", 55 | "@modelcontextprotocol/server-everything", 56 | ] 57 | 58 | [tasks.example-create-md-plain] 59 | command = "cargo" 60 | args = [ 61 | "run", 62 | "--", 63 | "create", 64 | "-t", 65 | "md-plain", 66 | "-f", 67 | "docs/examples/create-md-plain.md", 68 | "--", 69 | "npx", 70 | "-y", 71 | "@modelcontextprotocol/server-everything", 72 | ] 73 | 74 | [tasks.example-create-server-info-html] 75 | command = "cargo" 76 | args = [ 77 | "run", 78 | "--", 79 | "create", 80 | "-t", 81 | "html", 82 | "-f", 83 | "docs/examples/server-info.html", 84 | "--", 85 | "npx", 86 | "-y", 87 | "@modelcontextprotocol/server-everything", 88 | ] 89 | 90 | 91 | [tasks.example-update-md] 92 | command = "cargo" 93 | args = [ 94 | "run", 95 | "--", 96 | "update", 97 | "-t", 98 | "md", 99 | "-f", 100 | "docs/examples/update-md.md", 101 | "--", 102 | "npx", 103 | "-y", 104 | "@modelcontextprotocol/server-everything", 105 | ] 106 | 107 | 108 | [tasks.example-update-md-plain] 109 | command = "cargo" 110 | args = [ 111 | "run", 112 | "--", 113 | "update", 114 | "-t", 115 | "md-plain", 116 | "-f", 117 | "docs/examples/update-md-plain.md", 118 | "--", 119 | "npx", 120 | "-y", 121 | "@modelcontextprotocol/server-everything", 122 | ] 123 | 124 | 125 | [tasks.example-update-md-inline] 126 | command = "cargo" 127 | args = [ 128 | "run", 129 | "--", 130 | "update", 131 | "-f", 132 | "docs/examples/update-md-inline.md", 133 | "--", 134 | "npx", 135 | "-y", 136 | "@modelcontextprotocol/server-everything", 137 | ] 138 | 139 | 140 | [tasks.example-update-json] 141 | command = "cargo" 142 | args = [ 143 | "run", 144 | "--", 145 | "update", 146 | "-f", 147 | "docs/examples/json.txt", 148 | "-s", 149 | "{{json}}", 150 | "--", 151 | "npx", 152 | "-y", 153 | "@modelcontextprotocol/server-everything", 154 | ] 155 | -------------------------------------------------------------------------------- /docs/guide/mcp-discovery-markers.md: -------------------------------------------------------------------------------- 1 | # Defining Update Regions with Markers 2 | 3 | When using the `update` subcommand, `mcp-discovery` places capabilities between designated markers in the target file, which vary by file format and are typically comment lines. 4 | 5 | The update command simplifies the process for developers and maintainers to keep their MCP Server documentation current effortlessly. 6 | 7 | You can run the mcp-discovery update command anytime to refresh the file with the latest MCP Server capabilities. 8 | 9 | ### Marker Annotations 10 | 11 | - **Render Block Start** : **`mcp-discovery-render`** 12 | - **Render Block End** : **`mcp-discovery-render-end`** 13 | 14 | **👉** The mcp-discovery-render marker supports template and template-file properties as well. Check the examples below for details. 15 | 16 | You can optionally include an inline template identifier within the render block, enclosed by: 17 | 18 | - **Template Block Start**: **`mcp-discovery-template`** 19 | - **Template Block End**: **`mcp-discovery-template-end`** 20 | 21 | If a template annotation is detected within a render block, `mcp-discovery` will use it to render the output. This allows for customized templates without depending on built-in or external template files. Check the examples below for details: 22 | 23 | ### Sample Markdown file annotated with render block: 24 | 25 | ```md 26 | # Server Info and Capabilities 27 | 28 | 29 | 30 | Server Capabilities will be placed here... 31 | 32 | 33 | ``` 34 | 35 | ### Sample Markdown file, annotated with render block and template name: 36 | 37 | ```md 38 | # Server Info and Capabilities 39 | 40 | 41 | 42 | Server Capabilities will be placed here... 43 | 44 | 45 | ``` 46 | 47 | ### Sample Markdown file, annotated with render block and custom template file: 48 | 49 | ```md 50 | # Server Info and Capabilities 51 | 52 | 53 | 54 | Server Capabilities will be placed here... 55 | 56 | 57 | ``` 58 | 59 | ### Sample HTML file with annotations : 60 | 61 | ```html 62 | 63 | 64 | 65 | My MCP Server 66 | 67 | 68 |

MCP Server Details

69 |
70 | 71 | 72 | 73 |
74 | 75 | 76 | ``` 77 | 78 | ### Sample HTML file with inline template : 79 | 80 | ```html 81 |

MCP Server Details

82 |
83 | 84 | 93 | 94 |
95 | ``` 96 | 97 | Below is a screenshot showing the resulting HTML after the mcp-discovery update command is executed: 98 | 99 | MCP Discovery HTML Inline Template 100 | 101 | > You can execute the mcp-discovery update command whenever you need to refresh the file with the latest MCP Server capabilities. 102 | -------------------------------------------------------------------------------- /docs/examples/create-md-plain.md: -------------------------------------------------------------------------------- 1 | ## example-servers/everything 1.0.0 2 | | 🟢 Tools (10) | 🟢 Prompts (3) | 🟢 Resources (10) | 🟢 Logging | 🟢 Completions | 🔴 Experimental | 3 | | --- | --- | --- | --- | --- | --- | 4 | 5 | ## 🛠️ Tools (10) 6 | 7 | 8 | - **add** 9 | - Adds two numbers 10 | - **Inputs:** 11 | - a : number
12 | - b : number
13 | 14 | - **annotatedMessage** 15 | - Demonstrates how annotations can be used to provide metadata about content 16 | - **Inputs:** 17 | - includeImage : boolean
18 | - messageType : error|success|debug
19 | 20 | - **echo** 21 | - Echoes back the input 22 | - **Inputs:** 23 | - message : string
24 | 25 | - **getResourceLinks** 26 | - Returns multiple resource links that reference different types of resources 27 | - **Inputs:** 28 | - count : number
29 | 30 | - **getResourceReference** 31 | - Returns a resource reference that can be used by MCP clients 32 | - **Inputs:** 33 | - resourceId : number
34 | 35 | - **getTinyImage** 36 | - Returns the MCP_TINY_IMAGE 37 | 38 | - **longRunningOperation** 39 | - Demonstrates a long running operation with progress updates 40 | - **Inputs:** 41 | - duration : number
42 | - steps : number
43 | 44 | - **printEnv** 45 | - Prints all environment variables, helpful for debugging MCP server configuration 46 | 47 | - **sampleLLM** 48 | - Samples from an LLM using MCP's sampling feature 49 | - **Inputs:** 50 | - maxTokens : number
51 | - prompt : string
52 | 53 | - **structuredContent** 54 | - Returns structured content along with an output schema for client data validation 55 | - **Inputs:** 56 | - location : string
57 | 58 | 59 | ## 📝 Prompts (3) 60 | 61 | 62 | - **simple_prompt** 63 | - A prompt without arguments 64 | 65 | - **complex_prompt** 66 | - A prompt with arguments 67 | 68 | - **resource_prompt** 69 | - A prompt that includes an embedded resource reference 70 | 71 | ## 📄 Resources (10) 72 | 73 | 74 | - **Resource 1** 75 | 76 | - URI: test://static/resource/1 (text/plain) 77 | 78 | - **Resource 2** 79 | 80 | - URI: test://static/resource/2 (application/octet-stream) 81 | 82 | - **Resource 3** 83 | 84 | - URI: test://static/resource/3 (text/plain) 85 | 86 | - **Resource 4** 87 | 88 | - URI: test://static/resource/4 (application/octet-stream) 89 | 90 | - **Resource 5** 91 | 92 | - URI: test://static/resource/5 (text/plain) 93 | 94 | - **Resource 6** 95 | 96 | - URI: test://static/resource/6 (application/octet-stream) 97 | 98 | - **Resource 7** 99 | 100 | - URI: test://static/resource/7 (text/plain) 101 | 102 | - **Resource 8** 103 | 104 | - URI: test://static/resource/8 (application/octet-stream) 105 | 106 | - **Resource 9** 107 | 108 | - URI: test://static/resource/9 (text/plain) 109 | 110 | - **Resource 10** 111 | 112 | - URI: test://static/resource/10 (application/octet-stream) 113 | 114 | ## 🧩 Resource Templates (1) 115 | 116 | 117 | - **Static Resource** 118 | - A static resource with a numeric ID 119 | 120 | ◾ generated by [mcp-discovery](https://github.com/rust-mcp-stack/mcp-discovery) 121 | -------------------------------------------------------------------------------- /docs/examples/update-md-plain.md: -------------------------------------------------------------------------------- 1 | # Server Info and Capabilities 2 | 3 | 4 | ## example-servers/everything 1.0.0 5 | | 🟢 Tools (10) | 🟢 Prompts (3) | 🟢 Resources (10) | 🟢 Logging | 🟢 Completions | 🔴 Experimental | 6 | | --- | --- | --- | --- | --- | --- | 7 | 8 | ## 🛠️ Tools (10) 9 | 10 | 11 | - **add** 12 | - Adds two numbers 13 | - **Inputs:** 14 | - a : number
15 | - b : number
16 | 17 | - **annotatedMessage** 18 | - Demonstrates how annotations can be used to provide metadata about content 19 | - **Inputs:** 20 | - includeImage : boolean
21 | - messageType : error|success|debug
22 | 23 | - **echo** 24 | - Echoes back the input 25 | - **Inputs:** 26 | - message : string
27 | 28 | - **getResourceLinks** 29 | - Returns multiple resource links that reference different types of resources 30 | - **Inputs:** 31 | - count : number
32 | 33 | - **getResourceReference** 34 | - Returns a resource reference that can be used by MCP clients 35 | - **Inputs:** 36 | - resourceId : number
37 | 38 | - **getTinyImage** 39 | - Returns the MCP_TINY_IMAGE 40 | 41 | - **longRunningOperation** 42 | - Demonstrates a long running operation with progress updates 43 | - **Inputs:** 44 | - duration : number
45 | - steps : number
46 | 47 | - **printEnv** 48 | - Prints all environment variables, helpful for debugging MCP server configuration 49 | 50 | - **sampleLLM** 51 | - Samples from an LLM using MCP's sampling feature 52 | - **Inputs:** 53 | - maxTokens : number
54 | - prompt : string
55 | 56 | - **structuredContent** 57 | - Returns structured content along with an output schema for client data validation 58 | - **Inputs:** 59 | - location : string
60 | 61 | 62 | ## 📝 Prompts (3) 63 | 64 | 65 | - **simple_prompt** 66 | - A prompt without arguments 67 | 68 | - **complex_prompt** 69 | - A prompt with arguments 70 | 71 | - **resource_prompt** 72 | - A prompt that includes an embedded resource reference 73 | 74 | ## 📄 Resources (10) 75 | 76 | 77 | - **Resource 1** 78 | 79 | - URI: test://static/resource/1 (text/plain) 80 | 81 | - **Resource 2** 82 | 83 | - URI: test://static/resource/2 (application/octet-stream) 84 | 85 | - **Resource 3** 86 | 87 | - URI: test://static/resource/3 (text/plain) 88 | 89 | - **Resource 4** 90 | 91 | - URI: test://static/resource/4 (application/octet-stream) 92 | 93 | - **Resource 5** 94 | 95 | - URI: test://static/resource/5 (text/plain) 96 | 97 | - **Resource 6** 98 | 99 | - URI: test://static/resource/6 (application/octet-stream) 100 | 101 | - **Resource 7** 102 | 103 | - URI: test://static/resource/7 (text/plain) 104 | 105 | - **Resource 8** 106 | 107 | - URI: test://static/resource/8 (application/octet-stream) 108 | 109 | - **Resource 9** 110 | 111 | - URI: test://static/resource/9 (text/plain) 112 | 113 | - **Resource 10** 114 | 115 | - URI: test://static/resource/10 (application/octet-stream) 116 | 117 | ## 🧩 Resource Templates (1) 118 | 119 | 120 | - **Static Resource** 121 | - A static resource with a numeric ID 122 | 123 | ◾ generated by [mcp-discovery](https://github.com/rust-mcp-stack/mcp-discovery) 124 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # MCP Discovery 2 | 3 | A command-line tool written in Rust for discovering and documenting MCP Server capabilities. 4 | 5 | `mcp-discovery` launches an MCP Server using provided commands, queries its capabilities, tools, resources etc. 6 | It supports outputting the results in the terminal or saving them to files in [Markdown](https://github.com/rust-mcp-stack/mcp-discovery/blob/main/docs/examples/update-md.md#server-info-and-capabilities), [HTML](https://rust-mcp-stack.github.io/mcp-discovery/examples/server-info.html), [plain text](https://rust-mcp-stack.github.io/mcp-discovery/examples/capabilities.txt), JSON, or a custom template defined by you. 7 | 8 | Check the [project documentation](https://rust-mcp-stack.github.io/mcp-discovery) for instructions and [command examples](https://rust-mcp-stack.github.io/mcp-discovery/#/guide/command-examples). 9 | 10 | ## Features 💡 11 | 12 | - **Display MCP Details**: Output MCP Server information, including tools, resources, and capabilities, directly to the terminal. 13 | - **Generate Files**: Create files in Markdown (`.md`), HTML (`.html`), or plain text (`.txt`) formats with MCP Server details and capabilities. 14 | - **Update Files**: Modify existing Markdown, HTML, or text files by adding MCP Server capabilities within specified markers, enabling MCP Server developers to automatically maintain up-to-date documentation and repository README files. 15 | - **Flexible Output Customization**: Choose from built-in templates (`md`, `md-plain`, `html`, `txt`) or supply custom Handlebars templates for personalized output. 16 | - **MCP Discovery GitHub Action**: Integrate the mcp-discovery CLI as a GitHub Action to automate and maintain up-to-date MCP Server documentation in your development workflow. 17 | 18 | This open-source project leverages the [rust-mcp-sdk](https://github.com/rust-mcp-stack/rust-mcp-sdk) for seamless interaction with MCP Servers. 19 | 20 | 🌐 Check out the **rust-mcp-filesystem** [capabilities](https://rust-mcp-stack.github.io/rust-mcp-filesystem/#/capabilities) page for a sample output. 21 | 22 | ## Installation ⬇️ 23 | 24 | ### Running as CLI 25 | 26 | 27 | ##### **Shell script** 28 | 29 | 30 | 31 | ```sh 32 | curl --proto '=https' --tlsv1.2 -LsSf https://github.com/rust-mcp-stack/mcp-discovery/releases/download/v0.2.2/mcp-discovery-installer.sh | sh 33 | ``` 34 | 35 | ##### **PowerShell script** 36 | 37 | ```sh 38 | powershell -ExecutionPolicy Bypass -c "irm https://github.com/rust-mcp-stack/mcp-discovery/releases/download/v0.2.2/mcp-discovery-installer.ps1 | iex" 39 | ``` 40 | 41 | 42 | 43 | ##### **Homebrew** 44 | 45 | ```sh 46 | brew install rust-mcp-stack/tap/mcp-discovery 47 | ``` 48 | 49 | ##### **Cargo** 50 | 51 | ```sh 52 | cargo install mcp-discovery --locked 53 | ``` 54 | 55 | ##### **NPM** 56 | 57 | ```sh 58 | npm i -g @rustmcp/mcp-discovery@latest 59 | ``` 60 | > The npm package is provided for convenience. It runs the same underlying Rust binary but can be installed and used as a standard npm package. 61 | 62 | ### GitHub Action 63 | 64 | The easiest way to automate and maintain up-to-date MCP Server documentation , is to use mcp-discovery as a GitHub action. 65 | Please see [rust-mcp-stack/mcp-discovery-action](https://github.com/rust-mcp-stack/mcp-discovery-action) for installation and configuration instructions. 66 | 67 | ## Example 68 | 69 | - Print MCP Server capabilities to the terminal: 70 | 71 | ```sh 72 | mcp-discovery -- npx -y @modelcontextprotocol/server-everything 73 | ``` 74 | 75 | - Running the following command will start the `@modelcontextprotocol/server-everything` server and generate an HTML file listing the available tools and capabilities provided by the example server: 76 | 77 | ```sh 78 | mcp-discovery create -f server-info.html -- npx -y @modelcontextprotocol/server-everything 79 | ``` 80 | 81 | 📄 Click here to view generated html file 82 |

83 | 84 | ?> 💡 See [Example Commands](guide/command-examples.md) for more CLI usage examples across different configurations and scenarios. 85 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use path_clean::PathClean; 2 | 3 | use crate::{OutputTemplate, error::DiscoveryResult, types::Template}; 4 | use std::{ 5 | io::{self, ErrorKind}, 6 | path::{Path, PathBuf}, 7 | }; 8 | 9 | #[derive(Debug)] 10 | pub struct RenderTemplateInfo { 11 | pub rendered_template: String, 12 | pub render_location: (usize, usize), 13 | } 14 | 15 | #[derive(Debug)] 16 | pub struct UpdateTemplateInfo { 17 | /// Content of the file to be updated by mcp-discovery 18 | pub content: String, 19 | pub line_ending: String, 20 | pub render_locations: Vec, 21 | } 22 | 23 | pub fn line_ending(content: &str, line_number: Option) -> &str { 24 | let line_number = line_number.unwrap_or(1); 25 | let target = line_number.saturating_sub(1); // 0-based index 26 | 27 | if let Some(line) = content.lines().nth(target) { 28 | let start = line.as_ptr() as usize - content.as_ptr() as usize + line.len(); 29 | let next_chars = &content[start..]; 30 | if next_chars.starts_with("\r\n") { 31 | return "\r\n"; 32 | } else if next_chars.starts_with("\n") { 33 | return "\n"; 34 | } 35 | } 36 | "\n" // Default if line not found or no line ending 37 | } 38 | 39 | pub fn match_template( 40 | filename: Option<&PathBuf>, 41 | template: &Option