mirror of
https://github.com/modelcontextprotocol/servers.git
synced 2026-02-19 11:54:58 -05:00
Merge branch 'main' into update-dbhub
This commit is contained in:
55
README.md
55
README.md
@@ -80,6 +80,7 @@ Official integrations are maintained by companies building production ready MCP
|
||||
- <img height="12" width="12" src="https://www.datastax.com/favicon-32x32.png" alt="DataStax logo" /> **[Astra DB](https://github.com/datastax/astra-db-mcp)** - Comprehensive tools for managing collections and documents in a [DataStax Astra DB](https://www.datastax.com/products/datastax-astra) NoSQL database with a full range of operations such as create, update, delete, find, and associated bulk actions.
|
||||
- <img height="12" width="12" src="https://cdn.prod.website-files.com/66598898fd13d51606c3215d/66ccbfef13bd8bc19d587578_favicon-32x32.png" alt="Atla Logo" /> **[Atla](https://github.com/atla-ai/atla-mcp-server)** - Enable AI agents to interact with the [Atla API](https://docs.atla-ai.com/) for state-of-the-art LLMJ evaluation.
|
||||
- <img height="12" width="12" src="https://assets.atlan.com/assets/atlan-a-logo-blue-background.png" alt="Atlan Logo" /> **[Atlan](https://github.com/atlanhq/agent-toolkit/tree/main/modelcontextprotocol)** - The Atlan Model Context Protocol server allows you to interact with the [Atlan](https://www.atlan.com/) services through multiple tools.
|
||||
- <img height="12" width="12" src="https://www.atlassian.com/favicon.ico" alt="Atlassian Logo" /> **[Atlassian](https://www.atlassian.com/platform/remote-mcp-server)** - Securely interact with Jira work items and Confluence pages, and search across both.
|
||||
- <img height="12" width="12" src="https://res.oafimg.cn/-/737b3b3ffed9b19e/logo.png" alt="AtomGit Logo" /> **[AtomGit](https://atomgit.com/atomgit-open-source-ecosystem/atomgit-mcp-server)** - Official AtomGit server for integration with repository management, PRs, issues, branches, labels, and more.
|
||||
- <img height="12" width="12" src="https://resources.audiense.com/hubfs/favicon-1.png" alt="Audiense Logo" /> **[Audiense Insights](https://github.com/AudienseCo/mcp-audiense-insights)** - Marketing insights and audience analysis from [Audiense](https://www.audiense.com/products/audiense-insights) reports, covering demographic, cultural, influencer, and content engagement analysis.
|
||||
- <img height="12" width="12" src="https://cdn.auth0.com/website/website/favicons/auth0-favicon.svg" alt="Auth0 Logo" /> **[Auth0](https://github.com/auth0/auth0-mcp-server)** - MCP server for interacting with your Auth0 tenant, supporting creating and modifying actions, applications, forms, logs, resource servers, and more.
|
||||
@@ -113,6 +114,7 @@ Official integrations are maintained by companies building production ready MCP
|
||||
- <img height="12" width="12" src="https://clickhouse.com/favicon.ico" alt="ClickHouse Logo" /> **[ClickHouse](https://github.com/ClickHouse/mcp-clickhouse)** - Query your [ClickHouse](https://clickhouse.com/) database server.
|
||||
- <img src="http://www.google.com/s2/favicons?domain=www.cloudera.com" alt="Cloudera Iceberg" width="12" height="12"> **[Cloudera Iceberg](https://github.com/cloudera/iceberg-mcp-server)** - enabling AI on the [Open Data Lakehouse](https://www.cloudera.com/products/open-data-lakehouse.html).
|
||||
- <img height="12" width="12" src="https://cdn.simpleicons.org/cloudflare" /> **[Cloudflare](https://github.com/cloudflare/mcp-server-cloudflare)** - Deploy, configure & interrogate your resources on the Cloudflare developer platform (e.g. Workers/KV/R2/D1)
|
||||
- <img src="https://cdn.prod.website-files.com/64d41aab8183c7c3324ddb29/67c0f1e272e51cf3c511c17c_Gyph.svg" alt="Cloudinary" width="12" height="12"> **[Cloudinary](https://github.com/cloudinary/mcp-servers)** - Exposes Cloudinary's media upload, transformation, AI analysis, management, optimization and delivery as tools usable by AI agents
|
||||
- <img height="12" width="12" src="https://app.codacy.com/static/images/favicon-16x16.png" alt="Codacy Logo" /> **[Codacy](https://github.com/codacy/codacy-mcp-server/)** - Interact with [Codacy](https://www.codacy.com) API to query code quality issues, vulnerabilities, and coverage insights about your code.
|
||||
- <img height="12" width="12" src="https://codelogic.com/wp-content/themes/codelogic/assets/img/favicon.png" alt="CodeLogic Logo" /> **[CodeLogic](https://github.com/CodeLogicIncEngineering/codelogic-mcp-server)** - Interact with [CodeLogic](https://codelogic.com), a Software Intelligence platform that graphs complex code and data architecture dependencies, to boost AI accuracy and insight.
|
||||
- <img height="12" width="12" src="https://static.coingecko.com/s/coingecko-logo-white-750bdea438e850281f784dffc8f4fd498415754f088d655a1140849745cb66ac.svg" alt="CoinGecko Logo" /> **[CoinGecko](https://github.com/coingecko/coingecko-typescript/tree/main/packages/mcp-server)** - Official [CoinGecko API](https://www.coingecko.com/en/api) MCP Server for Crypto Price & Market Data, across 200+ Blockchain Networks and 8M+ Tokens.
|
||||
@@ -133,6 +135,7 @@ Official integrations are maintained by companies building production ready MCP
|
||||
- <img height="12" width="12" src="https://www.devhub.com/img/upload/favicon-196x196-dh.png" alt="DevHub Logo" /> **[DevHub](https://github.com/devhub/devhub-cms-mcp)** - Manage and utilize website content within the [DevHub](https://www.devhub.com) CMS platform
|
||||
- <img height="12" width="12" src="https://devrev.ai/favicon.ico" alt="DevRev Logo" /> **[DevRev](https://github.com/devrev/mcp-server)** - An MCP server to integrate with DevRev APIs to search through your DevRev Knowledge Graph where objects can be imported from diff. Sources listed [here](https://devrev.ai/docs/import#available-sources).
|
||||
- <img height="12" width="12" src="https://dexpaprika.com/favicon.ico" alt="DexPaprika Logo" /> **[DexPaprika (CoinPaprika)](https://github.com/coinpaprika/dexpaprika-mcp)** - Access real-time DEX data, liquidity pools, token information, and trading analytics across multiple blockchain networks with [DexPaprika](https://dexpaprika.com) by CoinPaprika.
|
||||
- <img height="12" width="12" src="https://drata.com/images/favicon.ico" alt="Drata Logo" /> **[Drata](https://drata.com/mcp)** - Get hands-on with our experimental MCP server—bringing real-time compliance intelligence into your AI workflows.
|
||||
- <img height="12" width="12" src="https://avatars.githubusercontent.com/u/204530939?s=200&v=4" alt="Dumpling AI Logo" /> **[Dumpling AI](https://github.com/Dumpling-AI/mcp-server-dumplingai)** - Access data, web scraping, and document conversion APIs by [Dumpling AI](https://www.dumplingai.com/)
|
||||
- <img height="12" width="12" src="https://avatars.githubusercontent.com/u/58178984" alt="Dynatrace Logo" /> **[Dynatrace](https://github.com/dynatrace-oss/dynatrace-mcp)** - Manage and interact with the [Dynatrace Platform ](https://www.dynatrace.com/platform) for real-time observability and monitoring.
|
||||
- <img height="12" width="12" src="https://e2b.dev/favicon.ico" alt="E2B Logo" /> **[E2B](https://github.com/e2b-dev/mcp-server)** - Run code in secure sandboxes hosted by [E2B](https://e2b.dev)
|
||||
@@ -143,6 +146,7 @@ Official integrations are maintained by companies building production ready MCP
|
||||
- <img height="12" width="12" src="https://esignatures.com/favicon.ico" alt="eSignatures Logo" /> **[eSignatures](https://github.com/esignaturescom/mcp-server-esignatures)** - Contract and template management for drafting, reviewing, and sending binding contracts.
|
||||
- <img height="12" width="12" src="https://exa.ai/images/favicon-32x32.png" alt="Exa Logo" /> **[Exa](https://github.com/exa-labs/exa-mcp-server)** - Search Engine made for AIs by [Exa](https://exa.ai)
|
||||
- **[FalkorDB](https://github.com/FalkorDB/FalkorDB-MCPServer)** - FalkorDB graph database server get schema and read/write-cypher [FalkorDB](https://www.falkordb.com)
|
||||
- <img height="12" width="12" src="https://fetchserp.com/icon.png" alt="fetchSERP Logo" /> **[fetchSERP](https://github.com/fetchSERP/fetchserp-mcp-server-node)** - All-in-One SEO & Web Intelligence Toolkit API [fetchSERP](https://www.fetchserp.com/)
|
||||
- <img height="12" width="12" src="https://fewsats.com/favicon.svg" alt="Fewsats Logo" /> **[Fewsats](https://github.com/Fewsats/fewsats-mcp)** - Enable AI Agents to purchase anything in a secure way using [Fewsats](https://fewsats.com)
|
||||
- <img height="12" width="12" src="https://fibery.io/favicon.svg" alt="Fibery Logo" /> **[Fibery](https://github.com/Fibery-inc/fibery-mcp-server)** - Perform queries and entity operations in your [Fibery](https://fibery.io) workspace.
|
||||
- <img height="12" width="12" src="https://financialdatasets.ai/favicon.ico" alt="Financial Datasets Logo" /> **[Financial Datasets](https://github.com/financial-datasets/mcp-server)** - Stock market API made for AI agents
|
||||
@@ -163,11 +167,14 @@ Official integrations are maintained by companies building production ready MCP
|
||||
- <img height="12" width="12" src="https://cdn.prod.website-files.com/6605a2979ff17b2cd1939cd4/6605a460de47e7596ed84f06_icon256.png" alt="gotoHuman Logo" /> **[gotoHuman](https://github.com/gotohuman/gotohuman-mcp-server)** - Human-in-the-loop platform - Allow AI agents and automations to send requests for approval to your [gotoHuman](https://www.gotohuman.com) inbox.
|
||||
- <img height="12" width="12" src="https://grafana.com/favicon.ico" alt="Grafana Logo" /> **[Grafana](https://github.com/grafana/mcp-grafana)** - Search dashboards, investigate incidents and query datasources in your Grafana instance
|
||||
- <img height="12" width="12" src="https://grafbase.com/favicon.ico" alt="Grafbase Logo" /> **[Grafbase](https://github.com/grafbase/grafbase/tree/main/crates/mcp)** - Turn your GraphQL API into an efficient MCP server with schema intelligence in a single command.
|
||||
- <img height="12" width="12" src="https://cdn.prod.website-files.com/5f5e90c17e7c9eb95c7acb17/61d3457a519242f2c75c725c_favicon.png" alt="Grain Logo" /> **[Grain](https://grain.com/release-note/06-18-2025)** - Add your Grain Meetings, Transcripts and Notes direction into your Grain API into Claude and other AI Chat clients.
|
||||
- <img height="12" width="12" src="https://framerusercontent.com/images/KCOWBYLKunDff1Dr452y6EfjiU.png" alt="Graphlit Logo" /> **[Graphlit](https://github.com/graphlit/graphlit-mcp-server)** - Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a searchable [Graphlit](https://www.graphlit.com) project.
|
||||
- <img height="12" width="12" src="https://greptime.com/favicon.ico" alt="Greptime Logo" /> **[GreptimeDB](https://github.com/GreptimeTeam/greptimedb-mcp-server)** - Provides AI assistants with a secure and structured way to explore and analyze data in [GreptimeDB](https://github.com/GreptimeTeam/greptimedb).
|
||||
- <img height="12" width="12" src="https://growi.org/assets/images/favicon.ico" alt="GROWI Logo" /> **[GROWI](https://github.com/growilabs/growi-mcp-server)** - Official MCP Server to integrate with GROWI APIs.
|
||||
- <img height="12" width="12" src="https://gyazo.com/favicon.ico" alt="Gyazo Logo" /> **[Gyazo](https://github.com/nota/gyazo-mcp-server)** - Search, fetch, upload, and interact with Gyazo images, including metadata and OCR data.
|
||||
- <img height="12" width="12" src="https://cdn.prod.website-files.com/6374050260446c42f94dc90f/63d828be3e13d32ee6973f35_favicon-32x32.png" alt="Harper Logo" /> **[Harper](https://github.com/HarperDB/mcp-server)** - An MCP server providing an interface for MCP clients to access data within [Harper](https://www.harpersystems.dev/).
|
||||
- <img height="12" width="12" src="https://www.herokucdn.com/favicons/favicon.ico" alt="Heroku Logo" /> **[Heroku](https://github.com/heroku/heroku-mcp-server)** - Interact with the Heroku Platform through LLM-driven tools for managing apps, add-ons, dynos, databases, and more.
|
||||
- <img height="12" width="12" src="https://www.hiveflow.ai/favicon.ico" alt="Hiveflow Logo" /> **[Hiveflow](https://github.com/hiveflowai/hiveflow-mcp-server)** - Create, manage, and execute agentic AI workflows directly from your assistant.
|
||||
- <img height="12" width="12" src="https://img.alicdn.com/imgextra/i3/O1CN01d9qrry1i6lTNa2BRa_!!6000000004364-2-tps-218-200.png" alt="Hologres Logo" /> **[Hologres](https://github.com/aliyun/alibabacloud-hologres-mcp-server)** - Connect to a [Hologres](https://www.alibabacloud.com/en/product/hologres) instance, get table metadata, query and analyze data.
|
||||
- <img height="12" width="12" src="https://www.honeycomb.io/favicon.ico" alt="Honeycomb Logo" /> **[Honeycomb](https://github.com/honeycombio/honeycomb-mcp)** Allows [Honeycomb](https://www.honeycomb.io/) Enterprise customers to query and analyze their data, alerts, dashboards, and more; and cross-reference production behavior with the codebase.
|
||||
- <img height="12" width="12" src="https://static.hsinfrastatic.net/StyleGuideUI/static-3.438/img/sprocket/favicon-32x32.png" alt="HubSpot Logo" /> **[HubSpot](https://developer.hubspot.com/mcp)** - Connect, manage, and interact with [HubSpot](https://www.hubspot.com/) CRM data
|
||||
@@ -180,12 +187,15 @@ Official integrations are maintained by companies building production ready MCP
|
||||
- <img height="12" width="12" src="https://www.inflectra.com/Favicon.ico" alt="Inflectra Logo" /> **[Inflectra Spira](https://github.com/Inflectra/mcp-server-spira)** - Connect to your instance of the SpiraTest, SpiraTeam or SpiraPlan application lifecycle management platform by [Inflectra](https://www.inflectra.com)
|
||||
- <img height="12" width="12" src="https://inkeep.com/favicon.ico" alt="Inkeep Logo" /> **[Inkeep](https://github.com/inkeep/mcp-server-python)** - RAG Search over your content powered by [Inkeep](https://inkeep.com)
|
||||
- <img height="12" width="12" src="https://integration.app/favicon.ico" alt="Integration App Icon" /> **[Integration App](https://github.com/integration-app/mcp-server)** - Interact with any other SaaS applications on behalf of your customers.
|
||||
- <img height="12" width="12" src="https://www.ip2location.io/favicon.ico" alt="IP2Location.io Icon" /> **[IP2Location.io](https://github.com/ip2location/mcp-ip2location-io)** - Interact with IP2Location.io API to retrieve the geolocation information for an IP address.
|
||||
- <img height="12" width="12" src="https://cdn.simpleicons.org/jetbrains" /> **[JetBrains](https://github.com/JetBrains/mcp-jetbrains)** – Work on your code with JetBrains IDEs
|
||||
- <img height="12" width="12" src="https://speedmedia.jfrog.com/08612fe1-9391-4cf3-ac1a-6dd49c36b276/media.jfrog.com/wp-content/uploads/2019/04/20131046/Jfrog16-1.png" alt="JFrog Logo" /> **[JFrog](https://github.com/jfrog/mcp-jfrog)** - Model Context Protocol (MCP) Server for the [JFrog](https://jfrog.com/) Platform API, enabling repository management, build tracking, release lifecycle management, and more.
|
||||
- <img height="12" width="12" src="https://kagi.com/favicon.ico" alt="Kagi Logo" /> **[Kagi Search](https://github.com/kagisearch/kagimcp)** - Search the web using Kagi's search API
|
||||
- <img height="12" width="12" src="https://connection.keboola.com/favicon.ico" alt="Keboola Logo" /> **[Keboola](https://github.com/keboola/keboola-mcp-server)** - Build robust data workflows, integrations, and analytics on a single intuitive platform.
|
||||
- <img height="12" width="12" src="https://keywordspeopleuse.com/favicon.ico" alt="KeywordsPeopleUse Logo" /> **[KeywordsPeopleUse.com](https://github.com/data-skunks/kpu-mcp)** - Find questions people ask online with [KeywordsPeopleUse](https://keywordspeopleuse.com).
|
||||
- <img height="12" width="12" src="https://raw.githubusercontent.com/klavis-ai/klavis/main/static/klavis-ai.png" alt="Klavis Logo" /> **[Klavis ReportGen](https://github.com/Klavis-AI/klavis/tree/main/mcp_servers/report_generation)** - Create professional reports from a simple user query.
|
||||
- <img height="12" width="12" src="https://www.klaviyo.com/media/Favicon-16by16.png" alt="Klaviyo Logo" /> **[Klaviyo](https://developers.klaviyo.com/en/docs/klaviyo_mcp_server)** - Interact with your [Klaviyo](https://www.klaviyo.com/) marketing data.
|
||||
- <img height="12" width="12" src="https://platform.kluster.ai/logo-light.svg" alt="kluster.ai Logo" /> **[kluster.ai](https://docs.kluster.ai/get-started/mcp/overview/)** - kluster.ai provides MCP servers that bring AI services directly into your development workflow, including guardrails like hallucination detection.
|
||||
- <img height="12" width="12" src="https://cdn.prod.website-files.com/6347ea26001f0287c592ff91/649953ef7a9ffe1f3e492b5a_Knit%20Logo.svg" alt="Knit Logo" /> **[Knit MCP Server](https://developers.getknit.dev/docs/knit-mcp-server-getting-started)** - Production-ready remote MCP servers that enable you to connect with 10000+ tools across CRM, HRIS, Payroll, Accounting, ERP, Calendar, Expense Management, and Chat categories.
|
||||
- <img height="12" width="12" src="https://knock.app/favicon/favicon-dark.svg" alt="Knock Logo" /> **[Knock MCP Server](https://github.com/knocklabs/agent-toolkit#model-context-protocol-mcp)** - Send product and customer messaging across email, in-app, push, SMS, Slack, MS Teams.
|
||||
- <img height="12" width="12" src="https://www.kurrent.io/favicon.ico" alt="Kurrent Logo" /> **[KurrentDB](https://github.com/kurrent-io/mcp-server)** - This is a simple MCP server to help you explore data and prototype projections faster on top of KurrentDB.
|
||||
@@ -209,6 +219,7 @@ Official integrations are maintained by companies building production ready MCP
|
||||
- <img height="12" width="12" src="https://www.mailgun.com/favicon.ico" alt="Mailgun Logo" /> **[Mailgun](https://github.com/mailgun/mailgun-mcp-server)** - Interact with Mailgun API.
|
||||
- <img height="12" width="12" src="https://www.make.com/favicon.ico" alt="Make Logo" /> **[Make](https://github.com/integromat/make-mcp-server)** - Turn your [Make](https://www.make.com/) scenarios into callable tools for AI assistants.
|
||||
- <img height="12" width="12" src="https://static-assets.mapbox.com/branding/favicon/v1/favicon.ico" alt="Mapbox Logo" /> **[Mapbox](https://github.com/mapbox/mcp-server)** - Unlock geospatial intelligence through Mapbox APIs like geocoding, POI search, directions, isochrones and more.
|
||||
- <img height="12" width="12" src="https://www.mariadb.com/favicon.ico" alt="MariaDB Logo" /> **[MariaDB](https://github.com/mariadb/mcp)** - A standard interface for managing and querying MariaDB databases, supporting both standard SQL operations and advanced vector/embedding-based search.
|
||||
- <img height="14" width="14" src="https://raw.githubusercontent.com/rust-mcp-stack/mcp-discovery/refs/heads/main/docs/_media/mcp-discovery-logo.png" alt="mcp-discovery logo" /> **[MCP Discovery](https://github.com/rust-mcp-stack/mcp-discovery)** - A lightweight CLI tool built in Rust for discovering MCP server capabilities.
|
||||
- <img height="12" width="12" src="https://googleapis.github.io/genai-toolbox/favicons/favicon.ico" alt="MCP Toolbox for Databases Logo" /> **[MCP Toolbox for Databases](https://github.com/googleapis/genai-toolbox)** - Open source MCP server specializing in easy, fast, and secure tools for Databases. Supports AlloyDB, BigQuery, Bigtable, Cloud SQL, Dgraph, MySQL, Neo4j, Postgres, Spanner, and more.
|
||||
- <img height="12" width="12" src="https://www.meilisearch.com/favicon.ico" alt="Meilisearch Logo" /> **[Meilisearch](https://github.com/meilisearch/meilisearch-mcp)** - Interact & query with Meilisearch (Full-text & semantic search API)
|
||||
@@ -218,11 +229,13 @@ Official integrations are maintained by companies building production ready MCP
|
||||
- <img height="12" width="12" src="https://metoro.io/static/images/logos/Metoro.svg" alt="Metoro Logo" /> **[Metoro](https://github.com/metoro-io/metoro-mcp-server)** - Query and interact with kubernetes environments monitored by Metoro
|
||||
- <img height="12" width="12" src="https://claritystatic.azureedge.net/images/logo.ico" alt="Microsoft Clarity Logo"/> **[Microsoft Clarity](https://github.com/microsoft/clarity-mcp-server)** - Official MCP Server to get your behavioral analytics data and insights from [Clarity](https://clarity.microsoft.com)
|
||||
- <img height="12" width="12" src="https://conn-afd-prod-endpoint-bmc9bqahasf3grgk.b01.azurefd.net/releases/v1.0.1735/1.0.1735.4099/commondataserviceforapps/icon.png" alt="Microsoft Dataverse Logo" /> **[Microsoft Dataverse](https://go.microsoft.com/fwlink/?linkid=2320176)** - Chat over your business data using NL - Discover tables, run queries, retrieve data, insert or update records, and execute custom prompts grounded in business knowledge and context.
|
||||
- <img height="12" width="12" src="https://www.microsoft.com/favicon.ico" alt="microsoft.com favicon" /> **[Microsoft Docs](https://github.com/microsoftdocs/mcp)** - An MCP server that provides structured access to Microsoft’s official documentation. Retrieves accurate, authoritative, and context-aware technical content for code generation, question answering, and workflow grounding.
|
||||
- <img height="12" width="12" src="https://www.microsoft.com/favicon.ico" alt="microsoft.com favicon" /> **[Microsoft Learn Docs](https://github.com/microsoftdocs/mcp)** - An MCP server that provides structured access to Microsoft’s official documentation. Retrieves accurate, authoritative, and context-aware technical content for code generation, question answering, and workflow grounding.
|
||||
- <img height="12" width="12" src="https://milvus.io/favicon-32x32.png" /> **[Milvus](https://github.com/zilliztech/mcp-server-milvus)** - Search, Query and interact with data in your Milvus Vector Database.
|
||||
- <img src="https://avatars.githubusercontent.com/u/94089762?s=48&v=4" alt="Mobb" width="12" height="12"> **[Mobb](https://github.com/mobb-dev/bugsy?tab=readme-ov-file#model-context-protocol-mcp-server)** - The [Mobb Vibe Shield](https://vibe.mobb.ai/) MCP server identifies and remediates vulnerabilities in both human and AI-written code, ensuring your applications remain secure without slowing development.
|
||||
- <img height="12" width="12" src="https://console.gomomento.com/favicon.ico" /> **[Momento](https://github.com/momentohq/mcp-momento)** - Momento Cache lets you quickly improve your performance, reduce costs, and handle load at any scale.
|
||||
- <img height="12" width="12" src="https://www.mongodb.com/favicon.ico" /> **[MongoDB](https://github.com/mongodb-js/mongodb-mcp-server)** - Both MongoDB Community Server and MongoDB Atlas are supported.
|
||||
- <img height="12" width="12" src="https://www.motherduck.com/favicon.ico" alt="MotherDuck Logo" /> **[MotherDuck](https://github.com/motherduckdb/mcp-server-motherduck)** - Query and analyze data with MotherDuck and local DuckDB
|
||||
- <img height="12" width="12" src="https://docs.mulesoft.com/_/img/favicon.ico" alt="Mulesoft Logo" /> **[Mulesoft](https://www.npmjs.com/package/@mulesoft/mcp-server)** - Build, deploy, and manage MuleSoft applications with natural language, directly inside any compatible IDE.
|
||||
- <img height="12" width="12" src="https://avatars.githubusercontent.com/u/38020270" alt="NanoVMs Logo" /> **[NanoVMs](https://github.com/nanovms/ops-mcp)** - Easily Build and Deploy unikernels to any cloud.
|
||||
- <img height="12" width="12" src="https://needle-ai.com/images/needle-logo-orange-2-rounded.png" alt="Needle AI Logo" /> **[Needle](https://github.com/needle-ai/needle-mcp)** - Production-ready RAG out of the box to search and retrieve data from your own documents.
|
||||
- <img height="12" width="12" src="https://neo4j.com/favicon.ico" alt="Neo4j Logo" /> **[Neo4j](https://github.com/neo4j-contrib/mcp-neo4j/)** - Neo4j graph database server (schema + read/write-cypher) and separate graph database backed memory
|
||||
@@ -295,11 +308,14 @@ Official integrations are maintained by companies building production ready MCP
|
||||
- <img height="12" width="12" src="https://semgrep.dev/favicon.ico" alt="Semgrep Logo" /> **[Semgrep](https://github.com/semgrep/mcp)** - Enable AI agents to secure code with [Semgrep](https://semgrep.dev/).
|
||||
- <img height="12" width="12" src="https://cdn.prod.website-files.com/6372338e5477e047032b37a5/64f85e6388a2a5c8c9525b4d_favLogo.png" alt="Shortcut Logo" /> **[Shortcut](https://github.com/useshortcut/mcp-server-shortcut)** - Access and implement all of your projects and tasks (Stories) from [Shortcut](https://shortcut.com/).
|
||||
- <img height="12" width="12" src="https://www.singlestore.com/favicon-32x32.png?v=277b9cbbe31e8bc416504cf3b902d430"/> **[SingleStore](https://github.com/singlestore-labs/mcp-server-singlestore)** - Interact with the SingleStore database platform
|
||||
- <img src="https://smooth-operator.online/logo48.png" alt="Smooth Operator" width="12" height="12"> **[Smooth Operator](https://smooth-operator.online/agent-tools-api-docs/toolserverdocs)** - Tools to automate Windows via AI Vision, Mouse, Keyboard, Automation Trees, Webbrowser
|
||||
- <img height="12" width="12" src="https://app.snyk.io/bundle/favicon-faj49uD9.png" alt="Snyk Logo" /> **[Snyk](https://github.com/snyk/snyk-ls/blob/main/mcp_extension/README.md)** - Enhance security posture by embedding [Snyk](https://snyk.io/) vulnerability scanning directly into agentic workflows.
|
||||
- <img height="12" width="12" src="https://www.sonarsource.com/favicon.ico" alt="SonarQube Logo" /> **[SonarQube](https://github.com/SonarSource/sonarqube-mcp-server)** - Enables seamless integration with [SonarQube](https://www.sonarsource.com/) Server or Cloud and allows for code snippet analysis within the agent context.
|
||||
- <img src="https://sophtron.com/favicon.ico" alt="Sophtron" width="12" height="12"> **[Sophtron](https://github.com/sophtron/Sophtron-Integration/tree/main/modelcontextprotocol)** - Connect to your bank, credit card, utilities accounts to retrieve account balances and transactions with [Sophtron Bank Integration](https://sophtron.com).
|
||||
- <img height="12" width="12" src="https://www.starrocks.io/favicon.ico" alt="StarRocks Logo" /> **[StarRocks](https://github.com/StarRocks/mcp-server-starrocks)** - Interact with [StarRocks](https://www.starrocks.io/)
|
||||
- <img height="12" width="12" src="https://downloads.steadybit.com/logomark.svg" alt="Steadybit Logo" /> **[Steadybit](https://github.com/steadybit/mcp)** - Interact with [Steadybit](https://www.steadybit.com/)
|
||||
- <img height="12" width="12" src="https://stripe.com/favicon.ico" alt="Stripe Logo" /> **[Stripe](https://github.com/stripe/agent-toolkit)** - Interact with Stripe API
|
||||
- <img height="12" width="12" src="https://supabase.com/favicon/favicon.ico" alt="Supabase Logo" /> **[Supabase](https://github.com/supabase-community/supabase-mcp)** - Interact with Supabase: Create tables, query data, deploy edge functions, and more.
|
||||
- <img height="12" width="12" src="https://d12w4pyrrczi5e.cloudfront.net/archive/50eb154ab859c63a8f1c850f9fe094e25d35e929/images/favicon.ico" alt="Tako Logo" /> **[Tako](https://github.com/TakoData/tako-mcp)** - Use natural language to search [Tako](https://trytako.com) for real-time financial, sports, weather, and public data with visualization
|
||||
- <img height="12" width="12" src="https://tavily.com/favicon.ico" alt="Tavily Logo" /> **[Tavily](https://github.com/tavily-ai/tavily-mcp)** - Search engine for AI agents (search + extract) powered by [Tavily](https://tavily.com/)
|
||||
- <img height="12" width="12" src="https://raw.githubusercontent.com/hashicorp/terraform-mcp-server/main/public/images/Terraform-LogoMark_onDark.svg" alt="Terraform Logo" /> **[Terraform](https://github.com/hashicorp/terraform-mcp-server)** - Seamlessly integrate with Terraform ecosystem, enabling advanced automation and interaction capabilities for Infrastructure as Code (IaC) development powered by [Terraform](https://www.hashicorp.com/en/products/terraform)
|
||||
@@ -311,6 +327,7 @@ Official integrations are maintained by companies building production ready MCP
|
||||
- <img height="12" width="12" src="https://www.pingcap.com/favicon.ico" alt="TiDB Logo" /> **[TiDB](https://github.com/pingcap/pytidb)** - MCP Server to interact with TiDB database platform.
|
||||
- <img height="12" width="12" src="https://www.tinybird.co/favicon.ico" alt="Tinybird Logo" /> **[Tinybird](https://github.com/tinybirdco/mcp-tinybird)** - Interact with Tinybird serverless ClickHouse platform
|
||||
- <img height="12" width="12" src="https://b2729162.smushcdn.com/2729162/wp-content/uploads/2023/10/cropped-Favicon-1-192x192.png?lossy=1&strip=1&webp=1" alt="Tldv Logo" /> **[Tldv](https://gitlab.com/tldv/tldv-mcp-server)** - Connect your AI agents to Google-Meet, Zoom & Microsoft Teams through [tl;dv](https://tldv.io)
|
||||
- <img height="12" width="12" src="https://cdn.tokenmetrics.com/logo.svg" alt="Token Metrics Logo" /> **[Token Metrics](https://github.com/token-metrics/mcp)** - [Token Metrics](https://www.tokenmetrics.com/) integration for fetching real-time crypto market data, trading signals, price predictions, and advanced analytics.
|
||||
- <img height="12" width="12" src="https://images.thetradeagent.ai/trade_agent/logo.svg" alt="Trade Agent Logo" /> **[Trade Agent](https://github.com/Trade-Agent/trade-agent-mcp)** - Execute stock and crypto trades on your brokerage via [Trade Agent](https://thetradeagent.ai)
|
||||
- <img height="12" width="12" src="https://www.twilio.com/content/dam/twilio-com/core-assets/social/favicon-16x16.png" alt="Twilio Logo" /> **[Twilio](https://github.com/twilio-labs/mcp)** - Interact with [Twilio](https://www.twilio.com/en-us) APIs to send SMS messages, manage phone numbers, configure your account, and more.
|
||||
- <img height="12" width="12" src="https://unifai.network/favicon.ico" alt="UnifAI Logo" /> **[UnifAI](https://github.com/unifai-network/unifai-mcp-server)** - Dynamically search and call tools using [UnifAI Network](https://unifai.network)
|
||||
@@ -325,6 +342,7 @@ Official integrations are maintained by companies building production ready MCP
|
||||
- <img height="12" width="12" src="https://www.veyrax.com/favicon.ico" alt="VeyraX Logo" /> **[VeyraX](https://github.com/VeyraX/veyrax-mcp)** - Single tool to control all 100+ API integrations, and UI components
|
||||
- <img height="12" width="12" src="https://avatars.githubusercontent.com/u/174736222?s=200&v=4" alt="VictoriaMetrics Logo" /> **[VictoriaMetrics](https://github.com/VictoriaMetrics-Community/mcp-victoriametrics)** - Comprehensive integration with [VictoriaMetrics APIs](https://docs.victoriametrics.com/victoriametrics/url-examples/) and [documentation](https://docs.victoriametrics.com/) for monitoring, observability, and debugging tasks related to your VictoriaMetrics instances.
|
||||
- <img src="https://framerusercontent.com/images/ijlYG00LOcMD6zR1XLMxHbAwZkM.png" alt="VideoDB Director" height="14"> **[VideoDB Director](https://github.com/video-db/agent-toolkit/tree/main/modelcontextprotocol)** - Create AI-powered video workflows including automatic editing, content moderation, voice cloning, highlight generation, and searchable video moments—all accessible via simple APIs and intuitive chat-based interfaces.
|
||||
- <img height="12" width="12" src="https://landing.ai/wp-content/uploads/2024/04/cropped-favicon-192x192.png" alt="LandingAI VisionAgent" /> **[VisionAgent MCP](https://github.com/landing-ai/vision-agent-mcp)** - A simple MCP server that enables your LLM to better reason over images, video and documents.
|
||||
- <img height="12" width="12" src="https://raw.githubusercontent.com/mckinsey/vizro/main/vizro-core/docs/assets/images/favicon.png" alt="Vizro Logo" /> **[Vizro](https://github.com/mckinsey/vizro/tree/main/vizro-mcp)** - Tools and templates to create validated and maintainable data charts and dashboards
|
||||
- <img height="12" width="12" src="https://wavespeed.ai/logo.webp" alt="WaveSpeed Logo" /> **[WaveSpeed](https://github.com/WaveSpeedAI/mcp-server)** - WaveSpeed MCP server providing AI agents with image and video generation capabilities.
|
||||
- <img height="12" width="12" src="https://waystation.ai/images/logo.svg" alt="WayStation Logo" /> **[WayStation](https://github.com/waystation-ai/mcp)** - Universal MCP server to connect to popular productivity tools such as Notion, Monday, AirTable, and many more
|
||||
@@ -350,7 +368,9 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[Ableton Live](https://github.com/ahujasid/ableton-mcp)** (by ahujasid) - Ableton integration allowing prompt enabled music creation.
|
||||
- **[Actor Critic Thinking](https://github.com/aquarius-wing/actor-critic-thinking-mcp)** - Actor-critic thinking for performance evaluation
|
||||
- **[AgentBay](https://github.com/Michael98671/agentbay)** - An MCP server for providing serverless cloud infrastructure for AI agents.
|
||||
- **[Ahrefs](https://github.com/universal-mcp/ahrefs)** - Ahrefs MCP server from **[agentr](https://agentr.dev/)** that provides programmatic access to SEO data, including backlinks, keywords, and site audit information.
|
||||
- **[AI Agent Marketplace Index](https://github.com/AI-Agent-Hub/ai-agent-marketplace-index-mcp)** - MCP server to search more than 5000+ AI agents and tools of various categories from [AI Agent Marketplace Index](http://www.deepnlp.org/store/ai-agent) and monitor traffic of AI Agents.
|
||||
- **[AI Tasks](https://github.com/jbrinkman/valkey-ai-tasks)** - Let the AI manage complex plans with integrated task management and tracking tools. Supports STDIO, SSE and Streamable HTTP transports.
|
||||
- **[ai-Bible](https://github.com/AdbC99/ai-bible)** - Search the bible reliably and repeatably [ai-Bible Labs](https://ai-bible.com)
|
||||
- **[Airbnb](https://github.com/openbnb-org/mcp-server-airbnb)** - Provides tools to search Airbnb and get listing details.
|
||||
- **[Airflow](https://github.com/yangkyeongmo/mcp-server-apache-airflow)** - A MCP Server that connects to [Apache Airflow](https://airflow.apache.org/) using official python client.
|
||||
@@ -373,6 +393,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[Arduino](https://github.com/vishalmysore/choturobo)** - MCP Server that enables AI-powered robotics using Claude AI and Arduino (ESP32) for real-world automation and interaction with robots.
|
||||
- **[arXiv API](https://github.com/prashalruchiranga/arxiv-mcp-server)** - An MCP server that enables interacting with the arXiv API using natural language.
|
||||
- **[arxiv-latex-mcp](https://github.com/takashiishida/arxiv-latex-mcp)** - MCP server that fetches and processes arXiv LaTeX sources for precise interpretation of mathematical expressions in papers.
|
||||
- **[Asana](https://github.com/universal-mcp/asana)** - Asana MCP server from **[agentr](https://agentr.dev/)** that provides support for managing tasks, projects, and work in Asana.
|
||||
- **[Atlassian](https://github.com/sooperset/mcp-atlassian)** - Interact with Atlassian Cloud products (Confluence and Jira) including searching/reading Confluence spaces/pages, accessing Jira issues, and project metadata.
|
||||
- **[Atlassian Server (by phuc-nt)](https://github.com/phuc-nt/mcp-atlassian-server)** - An MCP server that connects AI agents (Cline, Claude Desktop, Cursor, etc.) to Atlassian Jira & Confluence, enabling data queries and actions through the Model Context Protocol.
|
||||
- **[Attestable MCP](https://github.com/co-browser/attestable-mcp-server)** - An MCP server running inside a trusted execution environment (TEE) via Gramine, showcasing remote attestation using [RA-TLS](https://gramine.readthedocs.io/en/stable/attestation.html). This allows an MCP client to verify the server before conencting.
|
||||
@@ -399,6 +420,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[Bitable MCP](https://github.com/lloydzhou/bitable-mcp)** (by lloydzhou) - MCP server provides access to Lark Bitable through the Model Context Protocol. It allows users to interact with Bitable tables using predefined tools.
|
||||
- **[Blender](https://github.com/ahujasid/blender-mcp)** (by ahujasid) - Blender integration allowing prompt enabled 3D scene creation, modeling and manipulation.
|
||||
- **[BNBChain MCP](https://github.com/bnb-chain/bnbchain-mcp)** - An MCP server for interacting with BSC, opBNB, and the Greenfield blockchain.
|
||||
- **[Braze](https://github.com/universal-mcp/braze)** - Braze MCP server from **[agentr](https://agentr.dev/)** that provides support for managing customer engagement, user profiles, and messaging campaigns.
|
||||
- **[BreakoutRoom](https://github.com/agree-able/room-mcp)** - Agents accomplishing goals together in p2p rooms
|
||||
- **[browser-use](https://github.com/co-browser/browser-use-mcp-server)** (by co-browser) - browser-use MCP server with dockerized playwright + chromium + vnc. supports stdio & resumable http.
|
||||
- **[BrowserLoop](https://github.com/mattiasw/browserloop)** - An MCP server for taking screenshots of web pages using Playwright. Supports high-quality capture with configurable formats, viewport sizes, cookie-based authentication, and both full page and element-specific screenshots.
|
||||
@@ -407,6 +429,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[Calculator](https://github.com/githejie/mcp-server-calculator)** - This server enables LLMs to use calculator for precise numerical calculations.
|
||||
- **[CalDAV MCP](https://github.com/dominik1001/caldav-mcp)** - A CalDAV MCP server to expose calendar operations as tools for AI assistants.
|
||||
- **[Calendly](https://github.com/universal-mcp/calendly)** - Calendly MCP server from **[agentr](https://agentr.dev/)** that provides support for managing events and scheduling via Calendly.
|
||||
- **[Canva](https://github.com/universal-mcp/canva)** - Canva MCP server from **[agentr](https://agentr.dev/)** that provides support for managing tools of Canva App.
|
||||
- **[CCTV VMS MCP](https://github.com/jyjune/mcp_vms)** - A Model Context Protocol (MCP) server designed to connect to a CCTV recording program (VMS) to retrieve recorded and live video streams. It also provides tools to control the VMS software, such as showing live or playback dialogs for specific channels at specified times.
|
||||
- **[CFBD API](https://github.com/lenwood/cfbd-mcp-server)** - An MCP server for the [College Football Data API](https://collegefootballdata.com/).
|
||||
- **[ChatMCP](https://github.com/AI-QL/chat-mcp)** – An Open Source Cross-platform GUI Desktop application compatible with Linux, macOS, and Windows, enabling seamless interaction with MCP servers across dynamically selectable LLMs, by **[AIQL](https://github.com/AI-QL)**
|
||||
@@ -414,6 +437,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[Chess.com](https://github.com/pab1it0/chess-mcp)** - Access Chess.com player data, game records, and other public information through standardized MCP interfaces, allowing AI assistants to search and analyze chess information.
|
||||
- **[ChessPal Chess Engine (stockfish)](https://github.com/wilson-urdaneta/chesspal-mcp-engine)** - A Stockfish-powered chess engine exposed as an MCP server. Calculates best moves and supports both HTTP/SSE and stdio transports.
|
||||
- **[Chroma](https://github.com/privetin/chroma)** - Vector database server for semantic document search and metadata filtering, built on Chroma
|
||||
- **[CipherTrust Manager](https://github.com/sanyambassi/ciphertrust-manager-mcp-server)** - MCP server for Thales CipherTrust Manager integration, enabling secure key management and cryptographic operations.
|
||||
- **[Claude Thread Continuity](https://github.com/peless/claude-thread-continuity)** - Persistent memory system enabling Claude Desktop conversations to resume with full context across sessions. Maintains conversation history, project states, and user preferences for seamless multi-session workflows.
|
||||
- **[ClaudePost](https://github.com/ZilongXue/claude-post)** - ClaudePost enables seamless email management for Gmail, offering secure features like email search, reading, and sending.
|
||||
- **[ClickUp](https://github.com/TaazKareem/clickup-mcp-server)** - MCP server for ClickUp task management, supporting task creation, updates, bulk operations, and markdown descriptions.
|
||||
@@ -506,6 +530,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[FireCrawl](https://github.com/vrknetha/mcp-server-firecrawl)** - Advanced web scraping with JavaScript rendering, PDF support, and smart rate limiting
|
||||
- **[FitBit MCP Server](https://github.com/NitayRabi/fitbit-mcp)** - An MCP server that connects to FitBit API using a token obtained from OAuth flow.
|
||||
- **[FlightRadar24](https://github.com/sunsetcoder/flightradar24-mcp-server)** - A Claude Desktop MCP server that helps you track flights in real-time using Flightradar24 data.
|
||||
- **[Fluent-MCP](https://github.com/modesty/fluent-mcp)** - MCP server for Fluent (ServiceNow SDK) providing access to ServiceNow SDK CLI, API specifications, code snippets, and more.
|
||||
- **[Flyworks Avatar](https://github.com/Flyworks-AI/flyworks-mcp)** - Fast and free zeroshot lipsync MCP server.
|
||||
- **[FoundationModels](https://github.com/phimage/mcp-foundation-models)** - An MCP server that integrates Apple's [FoundationModels](https://developer.apple.com/documentation/foundationmodels) for text generation.
|
||||
- **[Foursquare](https://github.com/foursquare/foursquare-places-mcp)** - Enable your agent to recommend places around the world with the [Foursquare Places API](https://location.foursquare.com/products/places-api/)
|
||||
@@ -561,9 +586,12 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[iFlytek SparkAgent Platform](https://github.com/iflytek/ifly-spark-agent-mcp)** - This is a simple example of using MCP Server to invoke the task chain of the iFlytek SparkAgent Platform.
|
||||
- **[iFlytek Workflow](https://github.com/iflytek/ifly-workflow-mcp-server)** - Connect to iFlytek Workflow via the MCP server and run your own Agent.
|
||||
- **[Image Generation](https://github.com/GongRzhe/Image-Generation-MCP-Server)** - This MCP server provides image generation capabilities using the Replicate Flux model.
|
||||
- **[ImageSorcery MCP](https://github.com/sunriseapps/imagesorcery-mcp)** - ComputerVision-based 🪄 sorcery of image recognition and editing tools for AI assistants.
|
||||
- **[IMAP MCP](https://github.com/dominik1001/imap-mcp)** - 📧 An IMAP Model Context Protocol (MCP) server to expose IMAP operations as tools for AI assistants.
|
||||
- **[iMCP](https://github.com/loopwork-ai/iMCP)** - A macOS app that provides an MCP server for your iMessage, Reminders, and other Apple services.
|
||||
- **[InfluxDB](https://github.com/idoru/influxdb-mcp-server)** - Run queries against InfluxDB OSS API v2.
|
||||
- **[Inoyu](https://github.com/sergehuber/inoyu-mcp-unomi-server)** - Interact with an Apache Unomi CDP customer data platform to retrieve and update customer profiles
|
||||
- **[Instagram DM](https://github.com/trypeggy/instagram_dm_mcp)** - Send DMs on Instagram via your LLM
|
||||
- **[interactive-mcp](https://github.com/ttommyth/interactive-mcp)** - Enables interactive LLM workflows by adding local user prompts and chat capabilities directly into the MCP loop.
|
||||
- **[Intercom](https://github.com/raoulbia-ai/mcp-server-for-intercom)** - An MCP-compliant server for retrieving customer support tickets from Intercom. This tool enables AI assistants like Claude Desktop and Cline to access and analyze your Intercom support tickets.
|
||||
- **[iOS Simulator](https://github.com/InditexTech/mcp-server-simulator-ios-idb)** - A Model Context Protocol (MCP) server that enables LLMs to interact with iOS simulators (iPhone, iPad, etc.) through natural language commands.
|
||||
@@ -610,6 +638,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[lsp-mcp](https://github.com/Tritlo/lsp-mcp)** - Interact with Language Servers usint the Language Server Protocol to provide additional context information via hover, code actions and completions.
|
||||
- **[Lspace](https://github.com/Lspace-io/lspace-server)** - Turn scattered ChatGPT/Claude/Cursor conversations into persistent, searchable knowledge.
|
||||
- **[lucene-mcp-server](https://github.com/VivekKumarNeu/MCP-Lucene-Server)** - spring boot server using Lucene for fast document search and management.
|
||||
- **[LunarCrush Remote MCP](https://github.com/lunarcrush/mcp-server)** - Get the latest social metrics and posts for both current live social context as well as historical metrics in LLM and token optimized outputs. Ideal for automated trading / financial advisory.
|
||||
- **[mac-messages-mcp](https://github.com/carterlasalle/mac_messages_mcp)** - An MCP server that securely interfaces with your iMessage database via the Model Context Protocol (MCP), allowing LLMs to query and analyze iMessage conversations. It includes robust phone number validation, attachment processing, contact management, group chat handling, and full support for sending and receiving messages.
|
||||
- **[Maestro MCP](https://github.com/maestro-org/maestro-mcp)** - An MCP server for interacting with Bitcoin via the Maestro RPC API.
|
||||
- **[MalwareBazaar_MCP](https://github.com/mytechnotalent/MalwareBazaar_MCP)** (by Kevin Thomas) - An AI-driven MCP server that autonomously interfaces with MalwareBazaar, delivering real-time threat intel and sample metadata for authorized cybersecurity research workflows.
|
||||
@@ -634,6 +663,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[mcp-grep](https://github.com/erniebrodeur/mcp-grep)** - Python-based MCP server that brings grep functionality to LLMs. Supports common grep features including pattern searching, case-insensitive matching, context lines, and recursive directory searches.
|
||||
- **[mcp-k8s-go](https://github.com/strowk/mcp-k8s-go)** - Golang-based Kubernetes server for MCP to browse pods and their logs, events, namespaces and more. Built to be extensible.
|
||||
- **[mcp-local-rag](https://github.com/nkapila6/mcp-local-rag)** - "primitive" RAG-like web search model context protocol (MCP) server that runs locally using Google's MediaPipe Text Embedder and DuckDuckGo Search.
|
||||
- **[mcp-mcp](https://github.com/wojtyniak/mcp-mcp)** - Meta-MCP Server that acts as a tool discovery service for MCP clients.
|
||||
- **[mcp-meme-sticky](https://github.com/nkapila6/mcp-meme-sticky)** - Make memes or stickers using MCP server for WhatsApp or Telegram.
|
||||
- **[MCP-NixOS](https://github.com/utensils/mcp-nixos)** - A Model Context Protocol server that provides AI assistants with accurate, real-time information about NixOS packages, system options, Home Manager settings, and nix-darwin macOS configurations.
|
||||
- **[mcp-open-library](https://github.com/8enSmith/mcp-open-library)** - A Model Context Protocol (MCP) server for the Open Library API that enables AI assistants to search for book and author information.
|
||||
@@ -643,8 +673,10 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[mcp-server-leetcode](https://github.com/doggybee/mcp-server-leetcode)** - Practice and retrieve problems from LeetCode. Automate problem retrieval, solutions, and insights for coding practice and competitions.
|
||||
- **[mcp-vision](https://github.com/groundlight/mcp-vision)** - A MCP server exposing HuggingFace computer vision models such as zero-shot object detection as tools, enhancing the vision capabilities of large language or vision-language models.
|
||||
- **[mcp-weather](https://github.com/TimLukaHorstmann/mcp-weather)** - Accurate weather forecasts via the AccuWeather API (free tier available).
|
||||
- **[mcp-youtube-extract](https://github.com/sinjab/mcp_youtube_extract)** - A Model Context Protocol server for YouTube operations, extracting video information and transcripts with intelligent fallback logic. Features comprehensive logging, error handling, and support for both auto-generated and manual transcripts.
|
||||
- **[mcp_weather](https://github.com/isdaniel/mcp_weather_server)** - Get weather information from https://api.open-meteo.com API.
|
||||
- **[MCPIgnore Filesytem](https://github.com/CyberhavenInc/filesystem-mcpignore)** - A Data Security First filesystem MCP server that implements .mcpignore to prevent MCP clients from accessing sensitive data.
|
||||
- **[MeasureSpace MCP](https://github.com/MeasureSpace/measure-space-mcp-server)** - A free [Model Context Protocol (MCP) Server](https://smithery.ai/server/@MeasureSpace/measure-space-mcp-server) that provides global weather, climate, air quality forecast and geocoding services by [measurespace.io](https://measurespace.io).
|
||||
- **[MediaWiki](https://github.com/ProfessionalWiki/MediaWiki-MCP-Server)** - A Model Context Protocol (MCP) Server that interacts with any MediaWiki wiki
|
||||
- **[MediaWiki MCP adapter](https://github.com/lucamauri/MediaWiki-MCP-adapter)** - A custom Model Context Protocol adapter for MediaWiki and WikiBase APIs
|
||||
- **[mem0-mcp](https://github.com/mem0ai/mem0-mcp)** - A Model Context Protocol server for Mem0, which helps with managing coding preferences.
|
||||
@@ -694,6 +726,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[Obsidian Markdown Notes](https://github.com/calclavia/mcp-obsidian)** - Read and search through your Obsidian vault or any directory containing Markdown notes
|
||||
- **[obsidian-mcp](https://github.com/StevenStavrakis/obsidian-mcp)** - (by Steven Stavrakis) An MCP server for Obsidian.md with tools for searching, reading, writing, and organizing notes.
|
||||
- **[OceanBase](https://github.com/yuanoOo/oceanbase_mcp_server)** - (by yuanoOo) A Model Context Protocol (MCP) server that enables secure interaction with OceanBase databases.
|
||||
- **[Octocode](https://github.com/bgauryy/octocode-mcp)** - (by Guy Bary) AI-powered developer assistant that enables advanced code research, analysis and discovery across GitHub and NPM realms in realtime
|
||||
- **[Odoo](https://github.com/ivnvxd/mcp-server-odoo)** - Connect AI assistants to Odoo ERP systems for business data access and workflow automation.
|
||||
- **[Office-PowerPoint-MCP-Server](https://github.com/GongRzhe/Office-PowerPoint-MCP-Server)** - A Model Context Protocol (MCP) server for creating, reading, and manipulating Microsoft PowerPoint documents.
|
||||
- **[Office-Visio-MCP-Server](https://github.com/GongRzhe/Office-Visio-MCP-Server)** - A Model Context Protocol (MCP) server for creating, reading, and manipulating Microsoft Visio documents.
|
||||
@@ -702,6 +735,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[OneNote](https://github.com/rajvirtual/MCP-Servers/tree/master/onenote)** - (by Rajesh Vijay) An MCP server that connects to Microsoft OneNote using the Microsoft Graph API. Reading notebooks, sections, and pages from OneNote,Creating new notebooks, sections, and pages in OneNote.
|
||||
- **[Open Strategy Partners Marketing Tools](https://github.com/open-strategy-partners/osp_marketing_tools)** - Content editing codes, value map, and positioning tools for product marketing.
|
||||
- **[OpenAI WebSearch MCP](https://github.com/ConechoAI/openai-websearch-mcp)** - This is a Python-based MCP server that provides OpenAI `web_search` build-in tool.
|
||||
- **[OpenAlex.org MCP](https://github.com/drAbreu/alex-mcp)** - Professional MCP server providing ML-powered author disambiguation and comprehensive researcher profiles using the OpenAlex database.
|
||||
- **[OpenAPI](https://github.com/snaggle-ai/openapi-mcp-server)** - Interact with [OpenAPI](https://www.openapis.org/) APIs.
|
||||
- **[OpenAPI AnyApi](https://github.com/baryhuang/mcp-server-any-openapi)** - Interact with large [OpenAPI](https://www.openapis.org/) docs using built-in semantic search for endpoints. Allows for customizing the MCP server prefix.
|
||||
- **[OpenAPI Schema](https://github.com/hannesj/mcp-openapi-schema)** - Allow LLMs to explore large [OpenAPI](https://www.openapis.org/) schemas without bloating the context.
|
||||
@@ -710,8 +744,10 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[OpenCV](https://github.com/GongRzhe/opencv-mcp-server)** - A MCP server providing OpenCV computer vision capabilities. This allows AI assistants and language models to access powerful computer vision tools.
|
||||
- **[OpenDota](https://github.com/asusevski/opendota-mcp-server)** - Interact with OpenDota API to retrieve Dota 2 match data, player statistics, and more.
|
||||
- **[OpenRPC](https://github.com/shanejonas/openrpc-mpc-server)** - Interact with and discover JSON-RPC APIs via [OpenRPC](https://open-rpc.org).
|
||||
- **[OpenStack](https://github.com/wangsqly0407/openstack-mcp-server)** - MCP server implementation that provides OpenStack interaction.
|
||||
- **[OpenWeather](https://github.com/mschneider82/mcp-openweather)** - Interact with the free openweathermap API to get the current and forecast weather for a location.
|
||||
- **[OPNSense MCP](https://github.com/vespo92/OPNSenseMCP)** - MCP Server for OPNSense Firewall Management and API access
|
||||
- **[Optimade MCP](https://github.com/dianfengxiaobo/optimade-mcp-server)** - An MCP server conducts real-time material science data queries with the Optimade database (for example, elemental composition, crystal structure).
|
||||
- **[Oura Ring](https://github.com/rajvirtual/oura-mcp-server)** (by Rajesh Vijay) - MCP Server to access and analyze your Oura Ring data. It provides a structured way to fetch and understand your health metrics.
|
||||
- **[Outline](https://github.com/Vortiago/mcp-outline)** - MCP Server to interact with [Outline](https://www.getoutline.com) knowledge base to search, read, create, and manage documents and their content, access collections, add comments, and manage document backlinks.
|
||||
- **[pancakeswap-poolspy-mcp](https://github.com/kukapay/pancakeswap-poolspy-mcp)** - An MCP server that tracks newly created liquidity pools on Pancake Swap.
|
||||
@@ -737,6 +773,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[Puppeteer vision](https://github.com/djannot/puppeteer-vision-mcp)** - Use Puppeteer to browse a webpage and return a high quality Markdown. Use AI vision capabilities to handle cookies, captchas, and other interactive elements automatically.
|
||||
- **[Pushover](https://github.com/ashiknesin/pushover-mcp)** - Send instant notifications to your devices using [Pushover.net](https://pushover.net/)
|
||||
- **[pydantic/pydantic-ai/mcp-run-python](https://github.com/pydantic/pydantic-ai/tree/main/mcp-run-python)** - Run Python code in a secure sandbox via MCP tool calls, powered by Deno and Pyodide
|
||||
- **[Python CLI MCP](https://github.com/ofek/pycli-mcp)** - Interact with local Python command line applications.
|
||||
- **[QGIS](https://github.com/jjsantos01/qgis_mcp)** - connects QGIS to Claude AI through the MCP. This integration enables prompt-assisted project creation, layer loading, code execution, and more.
|
||||
- **[Qiniu MCP Server](https://github.com/qiniu/qiniu-mcp-server)** - The Model Context Protocol (MCP) Server built on Qiniu Cloud products supports users in accessing Qiniu Cloud Storage, intelligent multimedia services, and more through this MCP Server within the context of AI large model clients.
|
||||
- **[Quarkus](https://github.com/quarkiverse/quarkus-mcp-servers)** - MCP servers for the Quarkus Java framework.
|
||||
@@ -746,6 +783,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[RAG Local](https://github.com/renl/mcp-rag-local)** - This MCP server for storing and retrieving text passages locally based on their semantic meaning.
|
||||
- **[RAG Web Browser](https://github.com/apify/mcp-server-rag-web-browser)** An MCP server for Apify's open-source RAG Web Browser [Actor](https://apify.com/apify/rag-web-browser) to perform web searches, scrape URLs, and return content in Markdown.
|
||||
- **[Raindrop.io](https://github.com/hiromitsusasaki/raindrop-io-mcp-server)** - An integration that allows LLMs to interact with Raindrop.io bookmarks using the Model Context Protocol (MCP).
|
||||
- **[Random Number](https://github.com/zazencodes/random-number-mcp)** - Provides LLMs with essential random generation abilities, built entirely on Python's standard library.
|
||||
- **[Reaper](https://github.com/dschuler36/reaper-mcp-server)** - Interact with your [Reaper](https://www.reaper.fm/) (Digital Audio Workstation) projects.
|
||||
- **[Reddit](https://github.com/universal-mcp/reddit)** - Reddit MCP server from **[agentr](https://agentr.dev/)** that provides support for interacting with Reddit posts, comments, and subreddits.
|
||||
- **[Redis](https://github.com/GongRzhe/REDIS-MCP-Server)** - Redis database operations and caching microservice server with support for key-value operations, expiration management, and pattern-based key listing.
|
||||
@@ -761,7 +799,9 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[Rust MCP Filesystem](https://github.com/rust-mcp-stack/rust-mcp-filesystem)** - Fast, asynchronous MCP server for efficient handling of various filesystem operations built with the power of Rust.
|
||||
- **[Salesforce MCP](https://github.com/salesforce-mcp/salesforce-mcp)** - Salesforce MCP server. Supports cloud version Salesforce-mcp.com and allows both data & metadata functions.
|
||||
- **[Salesforce MCP](https://github.com/smn2gnt/MCP-Salesforce)** - Interact with Salesforce Data and Metadata
|
||||
- **[Salesforce MCP (AiondaDotCom)](https://github.com/AiondaDotCom/mcp-salesforce)** - Universal Salesforce integration with OAuth authentication, smart learning system, comprehensive backup capabilities, and full CRUD operations for any Salesforce org including custom objects and fields.
|
||||
- **[Salesforce MCP Server](https://github.com/tsmztech/mcp-server-salesforce)** - Comprehensive Salesforce integration with tools for querying records, executing Apex, managing fields/objects, and handling debug logs
|
||||
- **[SchemaCrawler](https://github.com/schemacrawler/SchemaCrawler-MCP-Server-Usage)** - Connect to any relational database, and be able to get valid SQL, and ask questions like what does a certain column prefix mean.
|
||||
- **[SchemaFlow](https://github.com/CryptoRadi/schemaflow-mcp-server)** - Real-time PostgreSQL & Supabase database schema access for AI-IDEs via Model Context Protocol. Provides live database context through secure SSE connections with three powerful tools: get_schema, analyze_database, and check_schema_alignment. [SchemaFlow](https://schemaflow.dev)
|
||||
- **[Scholarly](https://github.com/adityak74/mcp-scholarly)** - A MCP server to search for scholarly and academic articles.
|
||||
- **[scrapling-fetch](https://github.com/cyberchitta/scrapling-fetch-mcp)** - Access text content from bot-protected websites. Fetches HTML/markdown from sites with anti-automation measures using Scrapling.
|
||||
@@ -769,6 +809,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[SearXNG](https://github.com/erhwenkuo/mcp-searxng)** - A MCP server provide web searching via [SearXNG](https://docs.searxng.org) & retrieve url as makrdown.
|
||||
- **[SearXNG Public](https://github.com/pwilkin/mcp-searxng-public)** - A Model Context Protocol Server for retrieving data from public [SearXNG](https://docs.searxng.org) instances, with fallback support
|
||||
- **[SEC EDGAR](https://github.com/stefanoamorelli/sec-edgar-mcp)** - (by Stefano Amorelli) A community Model Context Protocol Server to access financial filings and data through the U.S. Securities and Exchange Commission ([SEC](https://www.sec.gov/)) `Electronic Data Gathering, Analysis, and Retrieval` ([EDGAR](https://www.sec.gov/submit-filings/about-edgar)) database
|
||||
- **[Semantic Scholar](https://github.com/universal-mcp/semanticscholar)** - Semantic Scholar MCP server from **[agentr](https://agentr.dev/)** that provides support for research using the Semnatic Scholar App.
|
||||
- **[SEO MCP](https://github.com/cnych/seo-mcp)** - A free SEO tool MCP (Model Control Protocol) service based on Ahrefs data. Includes features such as backlinks, keyword ideas, and more. by [claudemcp](https://www.claudemcp.com/servers/seo-mcp).
|
||||
- **[SerpApi](https://github.com/universal-mcp/serpapi)** - SerpApi MCP server from **[agentr](https://agentr.dev/)** that provides support for programmatic access to search engine results.
|
||||
- **[Serper](https://github.com/garymengcom/serper-mcp-server)** - An MCP server that performs Google searches using [Serper](https://serper.dev).
|
||||
@@ -804,6 +845,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[System Health](https://github.com/thanhtung0201/mcp-remote-system-health)** - The MCP (Multi-Channel Protocol) System Health Monitoring is a robust, real-time monitoring solution designed to provide comprehensive health metrics and alerts for remote Linux servers.
|
||||
- **[Talk To Figma](https://github.com/sonnylazuardi/cursor-talk-to-figma-mcp)** - This MCP server enables LLMs to interact with Figma, allowing them to read and modify designs programmatically.
|
||||
- **[Talk To Figma via Claude](https://github.com/gaganmanku96/talk-with-figma-claude)** - TMCP server that provides seamless Figma integration specifically for Claude Desktop, enabling design creation, modification, and real-time collaboration through natural language commands.
|
||||
- **[TAM MCP Server](https://github.com/gvaibhav/TAM-MCP-Server)** - Market research and business intelligence with TAM/SAM calculations and integration across 8 economic data sources: Alpha Vantage, BLS, Census Bureau, FRED, IMF, Nasdaq Data Link, OECD, and World Bank.
|
||||
- **[Tavily search](https://github.com/RamXX/mcp-tavily)** - An MCP server for Tavily's search & news API, with explicit site inclusions/exclusions
|
||||
- **[TeamRetro](https://github.com/adepanges/teamretro-mcp-server)** - This MCP server allows LLMs to interact with TeamRetro, allowing LLMs to manage user, team, team member, retrospective, health check, action, agreement and fetch the reports.
|
||||
- **[Telegram](https://github.com/chigwell/telegram-mcp)** - An MCP server that provides paginated chat reading, message retrieval, and message sending capabilities for Telegram through Telethon integration.
|
||||
@@ -839,6 +881,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[Unity Integration (Advanced)](https://github.com/quazaai/UnityMCPIntegration)** - Advanced Unity3d Game Engine MCP which supports ,Execution of Any Editor Related Code Directly Inside of Unity, Fetch Logs, Get Editor State and Allow File Access of the Project making it much more useful in Script Editing or asset creation.
|
||||
- **[Unity3d Game Engine](https://github.com/CoderGamester/mcp-unity)** - An MCP server that enables LLMs to interact with Unity3d Game Engine, supporting access to a variety of the Unit's Editor engine tools (e.g. Console Logs, Test Runner logs, Editor functions, hierarchy state, etc) and executing them as MCP tools or gather them as resources.
|
||||
- **[Unleash Integration (Feature Toggle)](https://github.com/cuongtl1992/unleash-mcp)** - A Model Context Protocol (MCP) server implementation that integrates with Unleash Feature Toggle system. Provide a bridge between LLM applications and Unleash feature flag system
|
||||
- **[use_aws_mcp](https://github.com/runjivu/use_aws_mcp)** - amazon-q-cli's use_aws tool extracted into independant mcp, for general aws api usage.
|
||||
- **[User Feedback](https://github.com/mrexodia/user-feedback-mcp)** - Simple MCP Server to enable a human-in-the-loop workflow in tools like Cline and Cursor.
|
||||
- **[USPTO](https://github.com/riemannzeta/patent_mcp_server)** - MCP server for accessing United States Patent & Trademark Office data through its Open Data Protocol (ODP) API.
|
||||
- **[Vectara](https://github.com/vectara/vectara-mcp)** - Query Vectara's trusted RAG-as-a-service platform.
|
||||
@@ -851,6 +894,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[Voice MCP](https://github.com/mbailey/voice-mcp)** - Enable voice conversations with Claude using any OpenAI-compatible STT/TTS service ([voice-mcp.com](https://voice-mcp.com))
|
||||
- **[VolcEngine TOS](https://github.com/dinghuazhou/sample-mcp-server-tos)** - A sample MCP server for VolcEngine TOS that flexibly get objects from TOS.
|
||||
- **[Voyp](https://github.com/paulotaylor/voyp-mcp)** - VOYP MCP server for making calls using Artificial Intelligence.
|
||||
- **[vulnicheck](https://github.com/andrasfe/vulnicheck)** - Real-time Python package vulnerability scanner that checks dependencies against OSV and NVD databases, providing comprehensive security analysis with CVE details, lock file support, and actionable upgrade recommendations.
|
||||
- **[Wanaku MCP Router](https://github.com/wanaku-ai/wanaku/)** - The Wanaku MCP Router is a SSE-based MCP server that provides an extensible routing engine that allows integrating your enterprise systems with AI agents.
|
||||
- **[weather-mcp-server](https://github.com/devilcoder01/weather-mcp-server)** - Get real-time weather data for any location using weatherapi.
|
||||
- **[Webflow](https://github.com/kapilduraphe/webflow-mcp-server)** - Interfact with the Webflow APIs
|
||||
@@ -858,11 +902,13 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[WhatsApp MCP Server](https://github.com/lharries/whatsapp-mcp)** - MCP server for your personal WhatsApp handling individuals, groups, searching and sending.
|
||||
- **[Whois MCP](https://github.com/bharathvaj-ganesan/whois-mcp)** - MCP server that performs whois lookup against domain, IP, ASN and TLD.
|
||||
- **[Wikidata MCP](https://github.com/zzaebok/mcp-wikidata)** - Wikidata MCP server that interact with Wikidata, by searching identifiers, extracting metadata, and executing sparql query.
|
||||
- **[Wikipedia MCP](https://github.com/Rudra-ravi/wikipedia-mcp)** - Access and search Wikipedia articles via MCP for AI-powered information retrieval.
|
||||
- **[WildFly MCP](https://github.com/wildfly-extras/wildfly-mcp)** - WildFly MCP server that enables LLM to interact with running WildFly servers (retrieve metrics, logs, invoke operations, ...).
|
||||
- **[Windows CLI](https://github.com/SimonB97/win-cli-mcp-server)** - MCP server for secure command-line interactions on Windows systems, enabling controlled access to PowerShell, CMD, and Git Bash shells.
|
||||
- **[Workflowy](https://github.com/danield137/mcp-workflowy)** - A server that interacts with [workflowy](https://workflowy.com/).
|
||||
- **[World Bank data API](https://github.com/anshumax/world_bank_mcp_server)** - A server that fetches data indicators available with the World Bank as part of their data API
|
||||
- **[Wren Engine](https://github.com/Canner/wren-engine)** - The Semantic Engine for Model Context Protocol(MCP) Clients and AI Agents
|
||||
- **[Wrike](https://github.com/universal-mcp/wrike)** - Wrike MCP server from **[agentr](https://agentr.dev/)** that provides support for managing projects, tasks, and workflows in Wrike.
|
||||
- **[X (Twitter)](https://github.com/EnesCinr/twitter-mcp)** (by EnesCinr) - Interact with twitter API. Post tweets and search for tweets by query.
|
||||
- **[X (Twitter)](https://github.com/vidhupv/x-mcp)** (by vidhupv) - Create, manage and publish X/Twitter posts directly through Claude chat.
|
||||
- **[Xcode](https://github.com/r-huijts/xcode-mcp-server)** - MCP server that brings AI to your Xcode projects, enabling intelligent code assistance, file operations, project management, and automated development tasks.
|
||||
@@ -875,6 +921,7 @@ A growing set of community-developed and maintained servers demonstrates various
|
||||
- **[YouTrack](https://github.com/tonyzorin/youtrack-mcp)** - A Model Context Protocol (MCP) server implementation for JetBrains YouTrack, allowing AI assistants to interact with YouTrack issue tracking system.
|
||||
- **[YouTube](https://github.com/Klavis-AI/klavis/tree/main/mcp_servers/youtube)** - Extract Youtube video information (with proxies support).
|
||||
- **[YouTube](https://github.com/ZubeidHendricks/youtube-mcp-server)** - Comprehensive YouTube API integration for video management, Shorts creation, and analytics.
|
||||
- **[Youtube Uploader MCP](https://github.com/anwerj/youtube-uploader-mcp)** - AI‑powered YouTube uploader—no CLI, no YouTube Studio.
|
||||
- **[YouTube Video Summarizer](https://github.com/nabid-pf/youtube-video-summarizer-mcp)** - Summarize lengthy youtube videos.
|
||||
- **[Zoom](https://github.com/Prathamesh0901/zoom-mcp-server/tree/main)** - Create, update, read and delete your zoom meetings.
|
||||
|
||||
@@ -893,13 +940,16 @@ These are high-level frameworks that make it easier to build MCP servers or clie
|
||||
* **[MCP Declarative Java SDK](https://github.com/codeboyzhou/mcp-declarative-java-sdk)** Annotation-driven MCP servers development with Java, no Spring Framework Required, minimize dependencies as much as possible.
|
||||
* **[MCP-Framework](https://mcp-framework.com)** Build MCP servers with elegance and speed in Typescript. Comes with a CLI to create your project with `mcp create app`. Get started with your first server in under 5 minutes by **[Alex Andru](https://github.com/QuantGeekDev)**
|
||||
* **[MCP Plexus](https://github.com/Super-I-Tech/mcp_plexus)**: A secure, **multi-tenant** and Multi-user MCP python server framework built to integrate easily with external services via OAuth 2.1, offering scalable and robust solutions for managing complex AI applications.
|
||||
* **[mcp_sse (Elixir)](https://github.com/kEND/mcp_sse)** An SSE implementation in Elixir for rapidly creating MCP servers.
|
||||
* **[Next.js MCP Server Template](https://github.com/vercel-labs/mcp-for-next.js)** (Typescript) - A starter Next.js project that uses the MCP Adapter to allow MCP clients to connect and access resources.
|
||||
* **[Quarkus MCP Server SDK](https://github.com/quarkiverse/quarkus-mcp-server)** (Java)
|
||||
* **[SAP ABAP MCP Server SDK](https://github.com/abap-ai/mcp)** - Build SAP ABAP based MCP servers. ABAP 7.52 based with 7.02 downport; runs on R/3 & S/4HANA on-premises, currently not cloud-ready.
|
||||
* **[Spring AI MCP Server](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html)** - Provides auto-configuration for setting up an MCP server in Spring Boot applications.
|
||||
* **[Template MCP Server](https://github.com/mcpdotdirect/template-mcp-server)** - A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
|
||||
* **[AgentR Universal MCP SDK](https://github.com/universal-mcp/universal-mcp)** - A python SDK to build MCP Servers with inbuilt credential management by **[Agentr](https://agentr.dev/home)**
|
||||
* **[Vercel MCP Adapter](https://github.com/vercel/mcp-adapter)** (Typescript) - A simple package to start serving an MCP server on most major JS meta-frameworks including Next, Nuxt, Svelte, and more.
|
||||
|
||||
|
||||
### For clients
|
||||
|
||||
* **[codemirror-mcp](https://github.com/marimo-team/codemirror-mcp)** - CodeMirror extension that implements the Model Context Protocol (MCP) for resource mentions and prompt commands
|
||||
@@ -921,6 +971,7 @@ Additional resources on MCP.
|
||||
- **[Discord Server (ModelContextProtocol)](https://discord.gg/jHEGxQu2a5)** – Connect with developers, share insights, and collaborate on projects in an active Discord community dedicated to the Model Context Protocol by **[Alex Andru](https://github.com/QuantGeekDev)**
|
||||
- <img height="12" width="12" src="https://raw.githubusercontent.com/klavis-ai/klavis/main/static/klavis-ai.png" alt="Klavis Logo" /> **[Klavis AI](https://www.klavis.ai)** - Open Source MCP Infra. Hosted MCP servers and MCP clients on Slack and Discord.
|
||||
- **[MCP Badges](https://github.com/mcpx-dev/mcp-badges)** – Quickly highlight your MCP project with clear, eye-catching badges, by **[Ironben](https://github.com/nanbingxyz)**
|
||||
- **[MCPRepository.com](https://mcprepository.com/)** - A repository that indexes and organizes all MCP servers for easy discovery.
|
||||
- **[mcp-cli](https://github.com/wong2/mcp-cli)** - A CLI inspector for the Model Context Protocol by **[wong2](https://github.com/wong2)**
|
||||
- **[mcp-dockmaster](https://mcp-dockmaster.com)** - An Open-Sourced UI to install and manage MCP servers for Windows, Linux and MacOS.
|
||||
- **[mcp-get](https://mcp-get.com)** - Command line tool for installing and managing MCP servers by **[Michael Latman](https://github.com/michaellatman)**
|
||||
@@ -933,6 +984,7 @@ Additional resources on MCP.
|
||||
- **[MCP Review](https://www.mcpreview.com)** - Website to list high quality MCP servers and reviews by real users. Also provide online playground for popular MCP servers.
|
||||
- **[MCP Router](https://mcp-router.net)** – Free Windows and macOS app that simplifies MCP management while providing seamless app authentication and powerful log visualization by **[MCP Router](https://github.com/mcp-router/mcp-router)**
|
||||
- **[MCP Servers Hub](https://github.com/apappascs/mcp-servers-hub)** (**[website](https://mcp-servers-hub-website.pages.dev/)**) - A curated list of MCP servers by **[apappascs](https://github.com/apappascs)**
|
||||
- **[MCPServers.com](https://mcpservers.com)** - A growing directory of high-quality MCP servers with clear setup guides for a variety of MCP clients. Built by the team behind the **[Highlight MCP client](https://highlightai.com/)**
|
||||
- **[MCP Servers Rating and User Reviews](http://www.deepnlp.org/store/ai-agent/mcp-server)** - Website to rate MCP servers, write authentic user reviews, and [search engine for agent & mcp](http://www.deepnlp.org/search/agent)
|
||||
- **[MCP X Community](https://x.com/i/communities/1861891349609603310)** – A X community for MCP by **[Xiaoyi](https://x.com/chxy)**
|
||||
- **[MCPHub](https://github.com/Jeamee/MCPHub-Desktop)** – An Open Source macOS & Windows GUI Desktop app for discovering, installing and managing MCP servers by **[Jeamee](https://github.com/jeamee)**
|
||||
@@ -945,6 +997,7 @@ Additional resources on MCP.
|
||||
- **[PulseMCP](https://www.pulsemcp.com)** ([API](https://www.pulsemcp.com/api)) - Community hub & weekly newsletter for discovering MCP servers, clients, articles, and news by **[Tadas Antanavicius](https://github.com/tadasant)**, **[Mike Coughlin](https://github.com/macoughl)**, and **[Ravina Patel](https://github.com/ravinahp)**
|
||||
- **[r/mcp](https://www.reddit.com/r/mcp)** – A Reddit community dedicated to MCP by **[Frank Fiegel](https://github.com/punkpeye)**
|
||||
- **[r/modelcontextprotocol](https://www.reddit.com/r/modelcontextprotocol)** – A Model Context Protocol community Reddit page - discuss ideas, get answers to your questions, network with like-minded people, and showcase your projects! by **[Alex Andru](https://github.com/QuantGeekDev)**
|
||||
- **[MCP.ing](https://mcp.ing/)** - A list of MCP services for discovering MCP servers in the community and providing a convenient search function for MCP services by **[iiiusky](https://github.com/iiiusky)**
|
||||
- **[Smithery](https://smithery.ai/)** - A registry of MCP servers to find the right tools for your LLM agents by **[Henry Mao](https://github.com/calclavia)**
|
||||
- **[Toolbase](https://gettoolbase.ai)** - Desktop application that manages tools and MCP servers with just a few clicks - no coding required by **[gching](https://github.com/gching)**
|
||||
- **[ToolHive](https://github.com/StacklokLabs/toolhive)** - A lightweight utility designed to simplify the deployment and management of MCP servers, ensuring ease of use, consistency, and security through containerization by **[StacklokLabs](https://github.com/StacklokLabs)**
|
||||
|
||||
844
src/filesystem/__tests__/path-validation.test.ts
Normal file
844
src/filesystem/__tests__/path-validation.test.ts
Normal file
@@ -0,0 +1,844 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as os from 'os';
|
||||
import { isPathWithinAllowedDirectories } from '../path-validation.js';
|
||||
|
||||
describe('Path Validation', () => {
|
||||
it('allows exact directory match', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project', allowed)).toBe(true);
|
||||
});
|
||||
|
||||
it('allows subdirectories', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/src', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/src/index.js', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/deeply/nested/file.txt', allowed)).toBe(true);
|
||||
});
|
||||
|
||||
it('blocks similar directory names (prefix vulnerability)', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project2', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project_backup', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project-old', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/projectile', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project.bak', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('blocks paths outside allowed directories', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
expect(isPathWithinAllowedDirectories('/home/user/other', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/etc/passwd', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('handles multiple allowed directories', () => {
|
||||
const allowed = ['/home/user/project1', '/home/user/project2'];
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project1/src', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project2/src', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project3', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project1_backup', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project2-old', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('blocks parent and sibling directories', () => {
|
||||
const allowed = ['/test/allowed'];
|
||||
|
||||
// Parent directory
|
||||
expect(isPathWithinAllowedDirectories('/test', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/', allowed)).toBe(false);
|
||||
|
||||
// Sibling with common prefix
|
||||
expect(isPathWithinAllowedDirectories('/test/allowed_sibling', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/test/allowed2', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('handles paths with special characters', () => {
|
||||
const allowed = ['/home/user/my-project (v2)'];
|
||||
|
||||
expect(isPathWithinAllowedDirectories('/home/user/my-project (v2)', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/my-project (v2)/src', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/my-project (v2)_backup', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/my-project', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
describe('Input validation', () => {
|
||||
it('rejects empty inputs', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
|
||||
expect(isPathWithinAllowedDirectories('', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project', [])).toBe(false);
|
||||
});
|
||||
|
||||
it('handles trailing separators correctly', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
|
||||
// Path with trailing separator should still match
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/', allowed)).toBe(true);
|
||||
|
||||
// Allowed directory with trailing separator
|
||||
const allowedWithSep = ['/home/user/project/'];
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project', allowedWithSep)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/', allowedWithSep)).toBe(true);
|
||||
|
||||
// Should still block similar names with or without trailing separators
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project2', allowedWithSep)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project2', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project2/', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('skips empty directory entries in allowed list', () => {
|
||||
const allowed = ['', '/home/user/project', ''];
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/src', allowed)).toBe(true);
|
||||
|
||||
// Should still validate properly with empty entries
|
||||
expect(isPathWithinAllowedDirectories('/home/user/other', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('handles Windows paths with trailing separators', () => {
|
||||
if (path.sep === '\\') {
|
||||
const allowed = ['C:\\Users\\project'];
|
||||
|
||||
// Path with trailing separator
|
||||
expect(isPathWithinAllowedDirectories('C:\\Users\\project\\', allowed)).toBe(true);
|
||||
|
||||
// Allowed with trailing separator
|
||||
const allowedWithSep = ['C:\\Users\\project\\'];
|
||||
expect(isPathWithinAllowedDirectories('C:\\Users\\project', allowedWithSep)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('C:\\Users\\project\\', allowedWithSep)).toBe(true);
|
||||
|
||||
// Should still block similar names
|
||||
expect(isPathWithinAllowedDirectories('C:\\Users\\project2\\', allowed)).toBe(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error handling', () => {
|
||||
it('normalizes relative paths to absolute', () => {
|
||||
const allowed = [process.cwd()];
|
||||
|
||||
// Relative paths get normalized to absolute paths based on cwd
|
||||
expect(isPathWithinAllowedDirectories('relative/path', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('./file', allowed)).toBe(true);
|
||||
|
||||
// Parent directory references that escape allowed directory
|
||||
const parentAllowed = ['/home/user/project'];
|
||||
expect(isPathWithinAllowedDirectories('../parent', parentAllowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for relative paths in allowed directories', () => {
|
||||
const badAllowed = ['relative/path', '/some/other/absolute/path'];
|
||||
|
||||
// Relative paths in allowed dirs are normalized to absolute based on cwd
|
||||
// The normalized 'relative/path' won't match our test path
|
||||
expect(isPathWithinAllowedDirectories('/some/other/absolute/path/file', badAllowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/absolute/path/file', badAllowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('handles null and undefined inputs gracefully', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
|
||||
// Should return false, not crash
|
||||
expect(isPathWithinAllowedDirectories(null as any, allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories(undefined as any, allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/path', null as any)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/path', undefined as any)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Unicode and special characters', () => {
|
||||
it('handles unicode characters in paths', () => {
|
||||
const allowed = ['/home/user/café'];
|
||||
|
||||
expect(isPathWithinAllowedDirectories('/home/user/café', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/café/file', allowed)).toBe(true);
|
||||
|
||||
// Different unicode representation won't match (not normalized)
|
||||
const decomposed = '/home/user/cafe\u0301'; // e + combining accent
|
||||
expect(isPathWithinAllowedDirectories(decomposed, allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('handles paths with spaces correctly', () => {
|
||||
const allowed = ['/home/user/my project'];
|
||||
|
||||
expect(isPathWithinAllowedDirectories('/home/user/my project', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/my project/file', allowed)).toBe(true);
|
||||
|
||||
// Partial matches should fail
|
||||
expect(isPathWithinAllowedDirectories('/home/user/my', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/my proj', allowed)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Overlapping allowed directories', () => {
|
||||
it('handles nested allowed directories correctly', () => {
|
||||
const allowed = ['/home', '/home/user', '/home/user/project'];
|
||||
|
||||
// All paths under /home are allowed
|
||||
expect(isPathWithinAllowedDirectories('/home/anything', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/anything', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/anything', allowed)).toBe(true);
|
||||
|
||||
// First match wins (most permissive)
|
||||
expect(isPathWithinAllowedDirectories('/home/other/deep/path', allowed)).toBe(true);
|
||||
});
|
||||
|
||||
it('handles root directory as allowed', () => {
|
||||
const allowed = ['/'];
|
||||
|
||||
// Everything is allowed under root (dangerous configuration)
|
||||
expect(isPathWithinAllowedDirectories('/', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/any/path', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/etc/passwd', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/secret', allowed)).toBe(true);
|
||||
|
||||
// But only on the same filesystem root
|
||||
if (path.sep === '\\') {
|
||||
expect(isPathWithinAllowedDirectories('D:\\other', ['/'])).toBe(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Cross-platform behavior', () => {
|
||||
it('handles Windows-style paths on Windows', () => {
|
||||
if (path.sep === '\\') {
|
||||
const allowed = ['C:\\Users\\project'];
|
||||
expect(isPathWithinAllowedDirectories('C:\\Users\\project', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('C:\\Users\\project\\src', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('C:\\Users\\project2', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('C:\\Users\\project_backup', allowed)).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('handles Unix-style paths on Unix', () => {
|
||||
if (path.sep === '/') {
|
||||
const allowed = ['/home/user/project'];
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/src', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project2', allowed)).toBe(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Validation Tests - Path Traversal', () => {
|
||||
it('blocks path traversal attempts', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
|
||||
// Basic traversal attempts
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/../../../etc/passwd', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/../../other', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/../project2', allowed)).toBe(false);
|
||||
|
||||
// Mixed traversal with valid segments
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/src/../../project2', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/./../../other', allowed)).toBe(false);
|
||||
|
||||
// Multiple traversal sequences
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/../project/../../../etc', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('blocks traversal in allowed directories', () => {
|
||||
const allowed = ['/home/user/project/../safe'];
|
||||
|
||||
// The allowed directory itself should be normalized and safe
|
||||
expect(isPathWithinAllowedDirectories('/home/user/safe/file', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/file', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('handles complex traversal patterns', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
|
||||
// Double dots in filenames (not traversal) - these normalize to paths within allowed dir
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/..test', allowed)).toBe(true); // Not traversal
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/test..', allowed)).toBe(true); // Not traversal
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/te..st', allowed)).toBe(true); // Not traversal
|
||||
|
||||
// Actual traversal
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/../test', allowed)).toBe(false); // Is traversal - goes to /home/user/test
|
||||
|
||||
// Edge case: /home/user/project/.. normalizes to /home/user (parent dir)
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/..', allowed)).toBe(false); // Goes to parent
|
||||
});
|
||||
});
|
||||
|
||||
describe('Validation Tests - Null Bytes', () => {
|
||||
it('rejects paths with null bytes', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project\x00/etc/passwd', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/test\x00.txt', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('\x00/home/user/project', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/\x00', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects allowed directories with null bytes', () => {
|
||||
const allowed = ['/home/user/project\x00'];
|
||||
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/file', allowed)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Validation Tests - Special Characters', () => {
|
||||
it('allows percent signs in filenames', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
|
||||
// Percent is a valid filename character
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/report_50%.pdf', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/Q1_25%_growth', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/%41', allowed)).toBe(true); // File named %41
|
||||
|
||||
// URL encoding is NOT decoded by path.normalize, so these are just odd filenames
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/%2e%2e', allowed)).toBe(true); // File named "%2e%2e"
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/file%20name', allowed)).toBe(true); // File with %20 in name
|
||||
});
|
||||
|
||||
it('handles percent signs in allowed directories', () => {
|
||||
const allowed = ['/home/user/project%20files'];
|
||||
|
||||
// This is a directory literally named "project%20files"
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project%20files/test', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project files/test', allowed)).toBe(false); // Different dir
|
||||
});
|
||||
});
|
||||
|
||||
describe('Path Normalization', () => {
|
||||
it('normalizes paths before comparison', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
|
||||
// Trailing slashes
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project//', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project///', allowed)).toBe(true);
|
||||
|
||||
// Current directory references
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/./src', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/./project/src', allowed)).toBe(true);
|
||||
|
||||
// Multiple slashes
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project//src//file', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home//user//project//src', allowed)).toBe(true);
|
||||
|
||||
// Should still block outside paths
|
||||
expect(isPathWithinAllowedDirectories('/home/user//project2', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('handles mixed separators correctly', () => {
|
||||
if (path.sep === '\\') {
|
||||
const allowed = ['C:\\Users\\project'];
|
||||
|
||||
// Mixed separators should be normalized
|
||||
expect(isPathWithinAllowedDirectories('C:/Users/project', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('C:\\Users/project\\src', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('C:/Users\\project/src', allowed)).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('rejects non-string inputs safely', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
|
||||
expect(isPathWithinAllowedDirectories(123 as any, allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories({} as any, allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories([] as any, allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories(null as any, allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories(undefined as any, allowed)).toBe(false);
|
||||
|
||||
// Non-string in allowed directories
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project', [123 as any])).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project', [{} as any])).toBe(false);
|
||||
});
|
||||
|
||||
it('handles very long paths', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
|
||||
// Create a very long path that's still valid
|
||||
const longSubPath = 'a/'.repeat(1000) + 'file.txt';
|
||||
expect(isPathWithinAllowedDirectories(`/home/user/project/${longSubPath}`, allowed)).toBe(true);
|
||||
|
||||
// Very long path that escapes
|
||||
const escapePath = 'a/'.repeat(1000) + '../'.repeat(1001) + 'etc/passwd';
|
||||
expect(isPathWithinAllowedDirectories(`/home/user/project/${escapePath}`, allowed)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Additional Coverage', () => {
|
||||
it('handles allowed directories with traversal that normalizes safely', () => {
|
||||
// These allowed dirs contain traversal but normalize to valid paths
|
||||
const allowed = ['/home/user/../user/project'];
|
||||
|
||||
// Should normalize to /home/user/project and work correctly
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/file', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/other', allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('handles symbolic dots in filenames', () => {
|
||||
const allowed = ['/home/user/project'];
|
||||
|
||||
// Single and double dots as actual filenames (not traversal)
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/.', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/..', allowed)).toBe(false); // This normalizes to parent
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/...', allowed)).toBe(true); // Three dots is a valid filename
|
||||
expect(isPathWithinAllowedDirectories('/home/user/project/....', allowed)).toBe(true); // Four dots is a valid filename
|
||||
});
|
||||
|
||||
it('handles UNC paths on Windows', () => {
|
||||
if (path.sep === '\\') {
|
||||
const allowed = ['\\\\server\\share\\project'];
|
||||
|
||||
expect(isPathWithinAllowedDirectories('\\\\server\\share\\project', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('\\\\server\\share\\project\\file', allowed)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories('\\\\server\\share\\other', allowed)).toBe(false);
|
||||
expect(isPathWithinAllowedDirectories('\\\\other\\share\\project', allowed)).toBe(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Symlink Tests', () => {
|
||||
let testDir: string;
|
||||
let allowedDir: string;
|
||||
let forbiddenDir: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'fs-error-test-'));
|
||||
allowedDir = path.join(testDir, 'allowed');
|
||||
forbiddenDir = path.join(testDir, 'forbidden');
|
||||
|
||||
await fs.mkdir(allowedDir, { recursive: true });
|
||||
await fs.mkdir(forbiddenDir, { recursive: true });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(testDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('validates symlink handling', async () => {
|
||||
// Test with symlinks
|
||||
try {
|
||||
const linkPath = path.join(allowedDir, 'bad-link');
|
||||
const targetPath = path.join(forbiddenDir, 'target.txt');
|
||||
|
||||
await fs.writeFile(targetPath, 'content');
|
||||
await fs.symlink(targetPath, linkPath);
|
||||
|
||||
// In real implementation, this would throw with the resolved path
|
||||
const realPath = await fs.realpath(linkPath);
|
||||
const allowed = [allowedDir];
|
||||
|
||||
// Symlink target should be outside allowed directory
|
||||
expect(isPathWithinAllowedDirectories(realPath, allowed)).toBe(false);
|
||||
} catch (error) {
|
||||
// Skip if no symlink permissions
|
||||
}
|
||||
});
|
||||
|
||||
it('handles non-existent paths correctly', async () => {
|
||||
const newFilePath = path.join(allowedDir, 'subdir', 'newfile.txt');
|
||||
|
||||
// Parent directory doesn't exist
|
||||
try {
|
||||
await fs.access(newFilePath);
|
||||
} catch (error) {
|
||||
expect((error as NodeJS.ErrnoException).code).toBe('ENOENT');
|
||||
}
|
||||
|
||||
// After creating parent, validation should work
|
||||
await fs.mkdir(path.dirname(newFilePath), { recursive: true });
|
||||
const allowed = [allowedDir];
|
||||
expect(isPathWithinAllowedDirectories(newFilePath, allowed)).toBe(true);
|
||||
});
|
||||
|
||||
// Test path resolution consistency for symlinked files
|
||||
it('validates symlinked files consistently between path and resolved forms', async () => {
|
||||
try {
|
||||
// Setup: Create target file in forbidden area
|
||||
const targetFile = path.join(forbiddenDir, 'target.txt');
|
||||
await fs.writeFile(targetFile, 'TARGET_CONTENT');
|
||||
|
||||
// Create symlink inside allowed directory pointing to forbidden file
|
||||
const symlinkPath = path.join(allowedDir, 'link-to-target.txt');
|
||||
await fs.symlink(targetFile, symlinkPath);
|
||||
|
||||
// The symlink path itself passes validation (looks like it's in allowed dir)
|
||||
expect(isPathWithinAllowedDirectories(symlinkPath, [allowedDir])).toBe(true);
|
||||
|
||||
// But the resolved path should fail validation
|
||||
const resolvedPath = await fs.realpath(symlinkPath);
|
||||
expect(isPathWithinAllowedDirectories(resolvedPath, [allowedDir])).toBe(false);
|
||||
|
||||
// Verify the resolved path goes to the forbidden location (normalize both paths for macOS temp dirs)
|
||||
expect(await fs.realpath(resolvedPath)).toBe(await fs.realpath(targetFile));
|
||||
} catch (error) {
|
||||
// Skip if no symlink permissions on the system
|
||||
if ((error as NodeJS.ErrnoException).code !== 'EPERM') {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Test allowed directory resolution behavior
|
||||
it('validates paths correctly when allowed directory is resolved from symlink', async () => {
|
||||
try {
|
||||
// Setup: Create the actual target directory with content
|
||||
const actualTargetDir = path.join(testDir, 'actual-target');
|
||||
await fs.mkdir(actualTargetDir, { recursive: true });
|
||||
const targetFile = path.join(actualTargetDir, 'file.txt');
|
||||
await fs.writeFile(targetFile, 'FILE_CONTENT');
|
||||
|
||||
// Setup: Create symlink directory that points to target
|
||||
const symlinkDir = path.join(testDir, 'symlink-dir');
|
||||
await fs.symlink(actualTargetDir, symlinkDir);
|
||||
|
||||
// Simulate resolved allowed directory (what the server startup should do)
|
||||
const resolvedAllowedDir = await fs.realpath(symlinkDir);
|
||||
const resolvedTargetDir = await fs.realpath(actualTargetDir);
|
||||
expect(resolvedAllowedDir).toBe(resolvedTargetDir);
|
||||
|
||||
// Test 1: File access through original symlink path should pass validation with resolved allowed dir
|
||||
const fileViaSymlink = path.join(symlinkDir, 'file.txt');
|
||||
const resolvedFile = await fs.realpath(fileViaSymlink);
|
||||
expect(isPathWithinAllowedDirectories(resolvedFile, [resolvedAllowedDir])).toBe(true);
|
||||
|
||||
// Test 2: File access through resolved path should also pass validation
|
||||
const fileViaResolved = path.join(resolvedTargetDir, 'file.txt');
|
||||
expect(isPathWithinAllowedDirectories(fileViaResolved, [resolvedAllowedDir])).toBe(true);
|
||||
|
||||
// Test 3: Demonstrate inconsistent behavior with unresolved allowed directories
|
||||
// If allowed dirs were not resolved (storing symlink paths instead):
|
||||
const unresolvedAllowedDirs = [symlinkDir];
|
||||
// This validation would incorrectly fail for the same content:
|
||||
expect(isPathWithinAllowedDirectories(resolvedFile, unresolvedAllowedDirs)).toBe(false);
|
||||
|
||||
} catch (error) {
|
||||
// Skip if no symlink permissions on the system
|
||||
if ((error as NodeJS.ErrnoException).code !== 'EPERM') {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('resolves nested symlink chains completely', async () => {
|
||||
try {
|
||||
// Setup: Create target file in forbidden area
|
||||
const actualTarget = path.join(forbiddenDir, 'target-file.txt');
|
||||
await fs.writeFile(actualTarget, 'FINAL_CONTENT');
|
||||
|
||||
// Create chain of symlinks: allowedFile -> link2 -> link1 -> actualTarget
|
||||
const link1 = path.join(testDir, 'intermediate-link1');
|
||||
const link2 = path.join(testDir, 'intermediate-link2');
|
||||
const allowedFile = path.join(allowedDir, 'seemingly-safe-file');
|
||||
|
||||
await fs.symlink(actualTarget, link1);
|
||||
await fs.symlink(link1, link2);
|
||||
await fs.symlink(link2, allowedFile);
|
||||
|
||||
// The allowed file path passes basic validation
|
||||
expect(isPathWithinAllowedDirectories(allowedFile, [allowedDir])).toBe(true);
|
||||
|
||||
// But complete resolution reveals the forbidden target
|
||||
const fullyResolvedPath = await fs.realpath(allowedFile);
|
||||
expect(isPathWithinAllowedDirectories(fullyResolvedPath, [allowedDir])).toBe(false);
|
||||
expect(await fs.realpath(fullyResolvedPath)).toBe(await fs.realpath(actualTarget));
|
||||
|
||||
} catch (error) {
|
||||
// Skip if no symlink permissions on the system
|
||||
if ((error as NodeJS.ErrnoException).code !== 'EPERM') {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Path Validation Race Condition Tests', () => {
|
||||
let testDir: string;
|
||||
let allowedDir: string;
|
||||
let forbiddenDir: string;
|
||||
let targetFile: string;
|
||||
let testPath: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'race-test-'));
|
||||
allowedDir = path.join(testDir, 'allowed');
|
||||
forbiddenDir = path.join(testDir, 'outside');
|
||||
targetFile = path.join(forbiddenDir, 'target.txt');
|
||||
testPath = path.join(allowedDir, 'test.txt');
|
||||
|
||||
await fs.mkdir(allowedDir, { recursive: true });
|
||||
await fs.mkdir(forbiddenDir, { recursive: true });
|
||||
await fs.writeFile(targetFile, 'ORIGINAL CONTENT', 'utf-8');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(testDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('validates non-existent file paths based on parent directory', async () => {
|
||||
const allowed = [allowedDir];
|
||||
|
||||
expect(isPathWithinAllowedDirectories(testPath, allowed)).toBe(true);
|
||||
await expect(fs.access(testPath)).rejects.toThrow();
|
||||
|
||||
const parentDir = path.dirname(testPath);
|
||||
expect(isPathWithinAllowedDirectories(parentDir, allowed)).toBe(true);
|
||||
});
|
||||
|
||||
it('demonstrates symlink race condition allows writing outside allowed directories', async () => {
|
||||
const allowed = [allowedDir];
|
||||
|
||||
await expect(fs.access(testPath)).rejects.toThrow();
|
||||
expect(isPathWithinAllowedDirectories(testPath, allowed)).toBe(true);
|
||||
|
||||
await fs.symlink(targetFile, testPath);
|
||||
await fs.writeFile(testPath, 'MODIFIED CONTENT', 'utf-8');
|
||||
|
||||
const targetContent = await fs.readFile(targetFile, 'utf-8');
|
||||
expect(targetContent).toBe('MODIFIED CONTENT');
|
||||
|
||||
const resolvedPath = await fs.realpath(testPath);
|
||||
expect(isPathWithinAllowedDirectories(resolvedPath, allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('shows timing differences between validation approaches', async () => {
|
||||
const allowed = [allowedDir];
|
||||
|
||||
const validation1 = isPathWithinAllowedDirectories(testPath, allowed);
|
||||
expect(validation1).toBe(true);
|
||||
|
||||
await fs.symlink(targetFile, testPath);
|
||||
|
||||
const resolvedPath = await fs.realpath(testPath);
|
||||
const validation2 = isPathWithinAllowedDirectories(resolvedPath, allowed);
|
||||
expect(validation2).toBe(false);
|
||||
|
||||
expect(validation1).not.toBe(validation2);
|
||||
});
|
||||
|
||||
it('validates directory creation timing', async () => {
|
||||
const allowed = [allowedDir];
|
||||
const testDir = path.join(allowedDir, 'newdir');
|
||||
|
||||
expect(isPathWithinAllowedDirectories(testDir, allowed)).toBe(true);
|
||||
|
||||
await fs.symlink(forbiddenDir, testDir);
|
||||
|
||||
expect(isPathWithinAllowedDirectories(testDir, allowed)).toBe(true);
|
||||
|
||||
const resolved = await fs.realpath(testDir);
|
||||
expect(isPathWithinAllowedDirectories(resolved, allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('demonstrates exclusive file creation behavior', async () => {
|
||||
const allowed = [allowedDir];
|
||||
|
||||
await fs.symlink(targetFile, testPath);
|
||||
|
||||
await expect(fs.open(testPath, 'wx')).rejects.toThrow(/EEXIST/);
|
||||
|
||||
await fs.writeFile(testPath, 'NEW CONTENT', 'utf-8');
|
||||
const targetContent = await fs.readFile(targetFile, 'utf-8');
|
||||
expect(targetContent).toBe('NEW CONTENT');
|
||||
});
|
||||
|
||||
it('should use resolved parent paths for non-existent files', async () => {
|
||||
const allowed = [allowedDir];
|
||||
|
||||
const symlinkDir = path.join(allowedDir, 'link');
|
||||
await fs.symlink(forbiddenDir, symlinkDir);
|
||||
|
||||
const fileThroughSymlink = path.join(symlinkDir, 'newfile.txt');
|
||||
|
||||
expect(fileThroughSymlink.startsWith(allowedDir)).toBe(true);
|
||||
|
||||
const parentDir = path.dirname(fileThroughSymlink);
|
||||
const resolvedParent = await fs.realpath(parentDir);
|
||||
expect(isPathWithinAllowedDirectories(resolvedParent, allowed)).toBe(false);
|
||||
|
||||
const expectedSafePath = path.join(resolvedParent, path.basename(fileThroughSymlink));
|
||||
expect(isPathWithinAllowedDirectories(expectedSafePath, allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('demonstrates parent directory symlink traversal', async () => {
|
||||
const allowed = [allowedDir];
|
||||
const deepPath = path.join(allowedDir, 'sub1', 'sub2', 'file.txt');
|
||||
|
||||
expect(isPathWithinAllowedDirectories(deepPath, allowed)).toBe(true);
|
||||
|
||||
const sub1Path = path.join(allowedDir, 'sub1');
|
||||
await fs.symlink(forbiddenDir, sub1Path);
|
||||
|
||||
await fs.mkdir(path.join(sub1Path, 'sub2'), { recursive: true });
|
||||
await fs.writeFile(deepPath, 'CONTENT', 'utf-8');
|
||||
|
||||
const realPath = await fs.realpath(deepPath);
|
||||
const realAllowedDir = await fs.realpath(allowedDir);
|
||||
const realForbiddenDir = await fs.realpath(forbiddenDir);
|
||||
|
||||
expect(realPath.startsWith(realAllowedDir)).toBe(false);
|
||||
expect(realPath.startsWith(realForbiddenDir)).toBe(true);
|
||||
});
|
||||
|
||||
it('should prevent race condition between validatePath and file operation', async () => {
|
||||
const allowed = [allowedDir];
|
||||
const racePath = path.join(allowedDir, 'race-file.txt');
|
||||
const targetFile = path.join(forbiddenDir, 'target.txt');
|
||||
|
||||
await fs.writeFile(targetFile, 'ORIGINAL CONTENT', 'utf-8');
|
||||
|
||||
// Path validation would pass (file doesn't exist, parent is in allowed dir)
|
||||
expect(await fs.access(racePath).then(() => false).catch(() => true)).toBe(true);
|
||||
expect(isPathWithinAllowedDirectories(racePath, allowed)).toBe(true);
|
||||
|
||||
// Race condition: symlink created after validation but before write
|
||||
await fs.symlink(targetFile, racePath);
|
||||
|
||||
// With exclusive write flag, write should fail on symlink
|
||||
await expect(
|
||||
fs.writeFile(racePath, 'NEW CONTENT', { encoding: 'utf-8', flag: 'wx' })
|
||||
).rejects.toThrow(/EEXIST/);
|
||||
|
||||
// Verify content unchanged
|
||||
const targetContent = await fs.readFile(targetFile, 'utf-8');
|
||||
expect(targetContent).toBe('ORIGINAL CONTENT');
|
||||
|
||||
// The symlink exists but write was blocked
|
||||
const actualWritePath = await fs.realpath(racePath);
|
||||
expect(actualWritePath).toBe(await fs.realpath(targetFile));
|
||||
expect(isPathWithinAllowedDirectories(actualWritePath, allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('should allow overwrites to legitimate files within allowed directories', async () => {
|
||||
const allowed = [allowedDir];
|
||||
const legitFile = path.join(allowedDir, 'legit-file.txt');
|
||||
|
||||
// Create a legitimate file
|
||||
await fs.writeFile(legitFile, 'ORIGINAL', 'utf-8');
|
||||
|
||||
// Opening with w should work for legitimate files
|
||||
const fd = await fs.open(legitFile, 'w');
|
||||
try {
|
||||
await fd.write('UPDATED', 0, 'utf-8');
|
||||
} finally {
|
||||
await fd.close();
|
||||
}
|
||||
|
||||
const content = await fs.readFile(legitFile, 'utf-8');
|
||||
expect(content).toBe('UPDATED');
|
||||
});
|
||||
|
||||
it('should handle symlinks that point within allowed directories', async () => {
|
||||
const allowed = [allowedDir];
|
||||
const targetFile = path.join(allowedDir, 'target.txt');
|
||||
const symlinkPath = path.join(allowedDir, 'symlink.txt');
|
||||
|
||||
// Create target file within allowed directory
|
||||
await fs.writeFile(targetFile, 'TARGET CONTENT', 'utf-8');
|
||||
|
||||
// Create symlink pointing to allowed file
|
||||
await fs.symlink(targetFile, symlinkPath);
|
||||
|
||||
// Opening symlink with w follows it to the target
|
||||
const fd = await fs.open(symlinkPath, 'w');
|
||||
try {
|
||||
await fd.write('UPDATED VIA SYMLINK', 0, 'utf-8');
|
||||
} finally {
|
||||
await fd.close();
|
||||
}
|
||||
|
||||
// Both symlink and target should show updated content
|
||||
const symlinkContent = await fs.readFile(symlinkPath, 'utf-8');
|
||||
const targetContent = await fs.readFile(targetFile, 'utf-8');
|
||||
expect(symlinkContent).toBe('UPDATED VIA SYMLINK');
|
||||
expect(targetContent).toBe('UPDATED VIA SYMLINK');
|
||||
});
|
||||
|
||||
it('should prevent overwriting files through symlinks pointing outside allowed directories', async () => {
|
||||
const allowed = [allowedDir];
|
||||
const legitFile = path.join(allowedDir, 'existing.txt');
|
||||
const targetFile = path.join(forbiddenDir, 'target.txt');
|
||||
|
||||
// Create a legitimate file first
|
||||
await fs.writeFile(legitFile, 'LEGIT CONTENT', 'utf-8');
|
||||
|
||||
// Create target file in forbidden directory
|
||||
await fs.writeFile(targetFile, 'FORBIDDEN CONTENT', 'utf-8');
|
||||
|
||||
// Now replace the legitimate file with a symlink to forbidden location
|
||||
await fs.unlink(legitFile);
|
||||
await fs.symlink(targetFile, legitFile);
|
||||
|
||||
// Simulate the server's validation logic
|
||||
const stats = await fs.lstat(legitFile);
|
||||
expect(stats.isSymbolicLink()).toBe(true);
|
||||
|
||||
const realPath = await fs.realpath(legitFile);
|
||||
expect(isPathWithinAllowedDirectories(realPath, allowed)).toBe(false);
|
||||
|
||||
// With atomic rename, symlinks are replaced not followed
|
||||
// So this test now demonstrates the protection
|
||||
|
||||
// Verify content remains unchanged
|
||||
const targetContent = await fs.readFile(targetFile, 'utf-8');
|
||||
expect(targetContent).toBe('FORBIDDEN CONTENT');
|
||||
});
|
||||
|
||||
it('demonstrates race condition in read operations', async () => {
|
||||
const allowed = [allowedDir];
|
||||
const legitFile = path.join(allowedDir, 'readable.txt');
|
||||
const secretFile = path.join(forbiddenDir, 'secret.txt');
|
||||
|
||||
// Create legitimate file
|
||||
await fs.writeFile(legitFile, 'PUBLIC CONTENT', 'utf-8');
|
||||
|
||||
// Create secret file in forbidden directory
|
||||
await fs.writeFile(secretFile, 'SECRET CONTENT', 'utf-8');
|
||||
|
||||
// Step 1: validatePath would pass for legitimate file
|
||||
expect(isPathWithinAllowedDirectories(legitFile, allowed)).toBe(true);
|
||||
|
||||
// Step 2: Race condition - replace file with symlink after validation
|
||||
await fs.unlink(legitFile);
|
||||
await fs.symlink(secretFile, legitFile);
|
||||
|
||||
// Step 3: Read operation follows symlink to forbidden location
|
||||
const content = await fs.readFile(legitFile, 'utf-8');
|
||||
|
||||
// This shows the vulnerability - we read forbidden content
|
||||
expect(content).toBe('SECRET CONTENT');
|
||||
expect(isPathWithinAllowedDirectories(await fs.realpath(legitFile), allowed)).toBe(false);
|
||||
});
|
||||
|
||||
it('verifies rename does not follow symlinks', async () => {
|
||||
const allowed = [allowedDir];
|
||||
const tempFile = path.join(allowedDir, 'temp.txt');
|
||||
const targetSymlink = path.join(allowedDir, 'target-symlink.txt');
|
||||
const forbiddenTarget = path.join(forbiddenDir, 'forbidden-target.txt');
|
||||
|
||||
// Create forbidden target
|
||||
await fs.writeFile(forbiddenTarget, 'ORIGINAL CONTENT', 'utf-8');
|
||||
|
||||
// Create symlink pointing to forbidden location
|
||||
await fs.symlink(forbiddenTarget, targetSymlink);
|
||||
|
||||
// Write temp file
|
||||
await fs.writeFile(tempFile, 'NEW CONTENT', 'utf-8');
|
||||
|
||||
// Rename temp file to symlink path
|
||||
await fs.rename(tempFile, targetSymlink);
|
||||
|
||||
// Check what happened
|
||||
const symlinkExists = await fs.lstat(targetSymlink).then(() => true).catch(() => false);
|
||||
const isSymlink = symlinkExists && (await fs.lstat(targetSymlink)).isSymbolicLink();
|
||||
const targetContent = await fs.readFile(targetSymlink, 'utf-8');
|
||||
const forbiddenContent = await fs.readFile(forbiddenTarget, 'utf-8');
|
||||
|
||||
// Rename should replace the symlink with a regular file
|
||||
expect(isSymlink).toBe(false);
|
||||
expect(targetContent).toBe('NEW CONTENT');
|
||||
expect(forbiddenContent).toBe('ORIGINAL CONTENT'); // Unchanged
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -10,10 +10,12 @@ import {
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import os from 'os';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { z } from "zod";
|
||||
import { zodToJsonSchema } from "zod-to-json-schema";
|
||||
import { diffLines, createTwoFilesPatch } from 'diff';
|
||||
import { minimatch } from 'minimatch';
|
||||
import { isPathWithinAllowedDirectories } from './path-validation.js';
|
||||
|
||||
// Command line argument parsing
|
||||
const args = process.argv.slice(2);
|
||||
@@ -34,9 +36,21 @@ function expandHome(filepath: string): string {
|
||||
return filepath;
|
||||
}
|
||||
|
||||
// Store allowed directories in normalized form
|
||||
const allowedDirectories = args.map(dir =>
|
||||
normalizePath(path.resolve(expandHome(dir)))
|
||||
// Store allowed directories in normalized and resolved form
|
||||
const allowedDirectories = await Promise.all(
|
||||
args.map(async (dir) => {
|
||||
const expanded = expandHome(dir);
|
||||
const absolute = path.resolve(expanded);
|
||||
try {
|
||||
// Resolve symlinks in allowed directories during startup
|
||||
const resolved = await fs.realpath(absolute);
|
||||
return normalizePath(resolved);
|
||||
} catch (error) {
|
||||
// If we can't resolve (doesn't exist), use the normalized absolute path
|
||||
// This allows configuring allowed dirs that will be created later
|
||||
return normalizePath(absolute);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Validate that all directories exist and are accessible
|
||||
@@ -63,7 +77,7 @@ async function validatePath(requestedPath: string): Promise<string> {
|
||||
const normalizedRequested = normalizePath(absolute);
|
||||
|
||||
// Check if path is within allowed directories
|
||||
const isAllowed = allowedDirectories.some(dir => normalizedRequested.startsWith(dir));
|
||||
const isAllowed = isPathWithinAllowedDirectories(normalizedRequested, allowedDirectories);
|
||||
if (!isAllowed) {
|
||||
throw new Error(`Access denied - path outside allowed directories: ${absolute} not in ${allowedDirectories.join(', ')}`);
|
||||
}
|
||||
@@ -72,25 +86,26 @@ async function validatePath(requestedPath: string): Promise<string> {
|
||||
try {
|
||||
const realPath = await fs.realpath(absolute);
|
||||
const normalizedReal = normalizePath(realPath);
|
||||
const isRealPathAllowed = allowedDirectories.some(dir => normalizedReal.startsWith(dir));
|
||||
if (!isRealPathAllowed) {
|
||||
throw new Error("Access denied - symlink target outside allowed directories");
|
||||
if (!isPathWithinAllowedDirectories(normalizedReal, allowedDirectories)) {
|
||||
throw new Error(`Access denied - symlink target outside allowed directories: ${realPath} not in ${allowedDirectories.join(', ')}`);
|
||||
}
|
||||
return realPath;
|
||||
} catch (error) {
|
||||
// For new files that don't exist yet, verify parent directory
|
||||
const parentDir = path.dirname(absolute);
|
||||
try {
|
||||
const realParentPath = await fs.realpath(parentDir);
|
||||
const normalizedParent = normalizePath(realParentPath);
|
||||
const isParentAllowed = allowedDirectories.some(dir => normalizedParent.startsWith(dir));
|
||||
if (!isParentAllowed) {
|
||||
throw new Error("Access denied - parent directory outside allowed directories");
|
||||
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
||||
const parentDir = path.dirname(absolute);
|
||||
try {
|
||||
const realParentPath = await fs.realpath(parentDir);
|
||||
const normalizedParent = normalizePath(realParentPath);
|
||||
if (!isPathWithinAllowedDirectories(normalizedParent, allowedDirectories)) {
|
||||
throw new Error(`Access denied - parent directory outside allowed directories: ${realParentPath} not in ${allowedDirectories.join(', ')}`);
|
||||
}
|
||||
return absolute;
|
||||
} catch {
|
||||
throw new Error(`Parent directory does not exist: ${parentDir}`);
|
||||
}
|
||||
return absolute;
|
||||
} catch {
|
||||
throw new Error(`Parent directory does not exist: ${parentDir}`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +346,19 @@ async function applyFileEdits(
|
||||
const formattedDiff = `${'`'.repeat(numBackticks)}diff\n${diff}${'`'.repeat(numBackticks)}\n\n`;
|
||||
|
||||
if (!dryRun) {
|
||||
await fs.writeFile(filePath, modifiedContent, 'utf-8');
|
||||
// Security: Use atomic rename to prevent race conditions where symlinks
|
||||
// could be created between validation and write. Rename operations
|
||||
// replace the target file atomically and don't follow symlinks.
|
||||
const tempPath = `${filePath}.${randomBytes(16).toString('hex')}.tmp`;
|
||||
try {
|
||||
await fs.writeFile(tempPath, modifiedContent, 'utf-8');
|
||||
await fs.rename(tempPath, filePath);
|
||||
} catch (error) {
|
||||
try {
|
||||
await fs.unlink(tempPath);
|
||||
} catch {}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return formattedDiff;
|
||||
@@ -625,7 +652,31 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
throw new Error(`Invalid arguments for write_file: ${parsed.error}`);
|
||||
}
|
||||
const validPath = await validatePath(parsed.data.path);
|
||||
await fs.writeFile(validPath, parsed.data.content, "utf-8");
|
||||
|
||||
try {
|
||||
// Security: 'wx' flag ensures exclusive creation - fails if file/symlink exists,
|
||||
// preventing writes through pre-existing symlinks
|
||||
await fs.writeFile(validPath, parsed.data.content, { encoding: "utf-8", flag: 'wx' });
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code === 'EEXIST') {
|
||||
// Security: Use atomic rename to prevent race conditions where symlinks
|
||||
// could be created between validation and write. Rename operations
|
||||
// replace the target file atomically and don't follow symlinks.
|
||||
const tempPath = `${validPath}.${randomBytes(16).toString('hex')}.tmp`;
|
||||
try {
|
||||
await fs.writeFile(tempPath, parsed.data.content, 'utf-8');
|
||||
await fs.rename(tempPath, validPath);
|
||||
} catch (renameError) {
|
||||
try {
|
||||
await fs.unlink(tempPath);
|
||||
} catch {}
|
||||
throw renameError;
|
||||
}
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
content: [{ type: "text", text: `Successfully wrote to ${parsed.data.path}` }],
|
||||
};
|
||||
|
||||
77
src/filesystem/path-validation.ts
Normal file
77
src/filesystem/path-validation.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Checks if an absolute path is within any of the allowed directories.
|
||||
*
|
||||
* @param absolutePath - The absolute path to check (will be normalized)
|
||||
* @param allowedDirectories - Array of absolute allowed directory paths (will be normalized)
|
||||
* @returns true if the path is within an allowed directory, false otherwise
|
||||
* @throws Error if given relative paths after normalization
|
||||
*/
|
||||
export function isPathWithinAllowedDirectories(absolutePath: string, allowedDirectories: string[]): boolean {
|
||||
// Type validation
|
||||
if (typeof absolutePath !== 'string' || !Array.isArray(allowedDirectories)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reject empty inputs
|
||||
if (!absolutePath || allowedDirectories.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reject null bytes (forbidden in paths)
|
||||
if (absolutePath.includes('\x00')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalize the input path
|
||||
let normalizedPath: string;
|
||||
try {
|
||||
normalizedPath = path.resolve(path.normalize(absolutePath));
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify it's absolute after normalization
|
||||
if (!path.isAbsolute(normalizedPath)) {
|
||||
throw new Error('Path must be absolute after normalization');
|
||||
}
|
||||
|
||||
// Check against each allowed directory
|
||||
return allowedDirectories.some(dir => {
|
||||
if (typeof dir !== 'string' || !dir) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reject null bytes in allowed dirs
|
||||
if (dir.includes('\x00')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalize the allowed directory
|
||||
let normalizedDir: string;
|
||||
try {
|
||||
normalizedDir = path.resolve(path.normalize(dir));
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify allowed directory is absolute after normalization
|
||||
if (!path.isAbsolute(normalizedDir)) {
|
||||
throw new Error('Allowed directories must be absolute paths after normalization');
|
||||
}
|
||||
|
||||
// Check if normalizedPath is within normalizedDir
|
||||
// Path is inside if it's the same or a subdirectory
|
||||
if (normalizedPath === normalizedDir) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Special case for root directory to avoid double slash
|
||||
if (normalizedDir === path.sep) {
|
||||
return normalizedPath.startsWith(path.sep);
|
||||
}
|
||||
|
||||
return normalizedPath.startsWith(normalizedDir + path.sep);
|
||||
});
|
||||
}
|
||||
@@ -265,7 +265,7 @@ Follow these steps for each interaction:
|
||||
- If any new information was gathered during the interaction, update your memory as follows:
|
||||
a) Create entities for recurring organizations, people, and significant events
|
||||
b) Connect them to the current entities using relations
|
||||
b) Store facts about them as observations
|
||||
c) Store facts about them as observations
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
Reference in New Issue
Block a user