Custom FastMCP Control Duplicate File In Project
No description available
Ask AI about Custom FastMCP Control Duplicate File In Project
Powered by Claude Β· Grounded in docs
I know everything about Custom FastMCP Control Duplicate File In Project. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
qa-mcp-server
Production-ready MCP (Model Context Protocol) governance server for Playwright BDD automation.
Acts as a central gatekeeper that prevents duplicate test creation, enforces BDD structure, reuses existing steps, blocks invalid file creation, and detects duplicate logic using AST analysis.
Table of Contents
- Project Structure
- Installation
- Configuration
- Running the Server
- Connecting to Claude
- Tools Reference
- How the Registry Works
- Governance Rules
- Extending the Server
Project Structure
qa-mcp-server/
βββ server.py β MCP entry point, all tools registered here
βββ tools/
β βββ feature_duplicate.py β Gherkin duplicate detection (Jaccard β₯ 0.85)
β βββ step_mapper.py β Step definition lookup in .ts files
β βββ ast_detector.py β Structural spec similarity (tree-sitter)
β βββ file_validator.py β File creation gatekeeper
β βββ structure_validator.py β BDD 3-file completeness check
β βββ intent_parser.py β User story β structured JSON intent
βββ utils/
β βββ gherkin_parser.py β Lightweight .feature file parser
β βββ ast_parser.py β tree-sitter / regex fingerprint extractor
β βββ similarity.py β Jaccard similarity functions
β βββ file_utils.py β Shared file I/O helpers
βββ registry/
β βββ test_registry.json β JIRA β Feature β Test mapping store
βββ config/
β βββ rules.py β Naming and creation rules
β βββ settings.py β Paths and similarity thresholds
βββ logs/
β βββ mcp.log β Append-only decision log
βββ requirements.txt
Installation
# 1. Clone / copy the project
cd qa-mcp-server
# 2. Create and activate a virtual environment (recommended)
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# 3. Install dependencies
pip install -r requirements.txt
Python 3.11+ is required.
Configuration
All configuration lives in config/settings.py. The most important settings can be overridden via environment variables:
| Environment Variable | Default | Description |
|---|---|---|
QA_PROJECT_ROOT | ./playwright-project | Root path of the Playwright BDD project being governed |
QA_REGISTRY_PATH | ./registry/test_registry.json | Path to the test registry file |
QA_LOG_PATH | ./logs/mcp.log | Path to the log file |
MCP_HOST | 0.0.0.0 | Host for the MCP HTTP server |
MCP_PORT | 8000 | Port for the MCP HTTP server |
Example:
export QA_PROJECT_ROOT=/home/ci/playwright-bdd
export MCP_PORT=9000
python server.py
Similarity Thresholds
Edit config/settings.py to tune detection sensitivity:
FEATURE_DUPLICATE_THRESHOLD = 0.85 # Feature Jaccard β mark as duplicate
AST_BLOCK_THRESHOLD = 0.90 # Spec AST Jaccard β block creation
AST_WARN_THRESHOLD = 0.75 # Spec AST Jaccard β warn
Running the Server
# From the qa-mcp-server directory
python server.py
Output:
2025-01-01 12:00:00 INFO qa_mcp.server β Starting qa-mcp-server on 0.0.0.0:8000 (transport=streamable-http)
The server listens on http://0.0.0.0:8000/mcp by default.
Connecting to Claude
Claude Desktop (claude_desktop_config.json)
Add the following entry to your Claude Desktop MCP configuration:
{
"mcpServers": {
"qa-mcp-server": {
"type": "streamable-http",
"url": "http://localhost:8000/mcp",
"description": "QA governance β Playwright BDD gatekeeper"
}
}
}
Config file locations:
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
Claude Code / API
import anthropic
client = anthropic.Anthropic()
# The MCP server is registered as a remote tool server
response = client.beta.messages.create(
model="claude-opus-4-5",
max_tokens=4096,
mcp_servers=[
{
"type": "url",
"url": "http://localhost:8000/mcp",
"name": "qa-mcp-server",
}
],
messages=[{"role": "user", "content": "Check if this feature already exists: ..."}],
)
Tools Reference
check_feature_duplicate
Detects semantically duplicate .feature files using Jaccard similarity on normalised BDD steps.
Inputs:
| Field | Type | Description |
|---|---|---|
feature_text | string | Raw Gherkin content of the proposed feature |
feature_filename | string | Intended filename (e.g. user_login.feature) |
Output:
{
"allowed": false,
"status": "duplicate",
"matches": [
{ "file": "features/login.feature", "similarity": 0.912 }
],
"message": "Feature 'user_login.feature' is too similar to existing features..."
}
find_existing_step
Searches all .ts step definition files for a matching step definition.
Inputs:
| Field | Type | Description |
|---|---|---|
step_text | string | Plain-text Gherkin step |
Output:
{
"found": true,
"file": "steps/login_steps.ts",
"matched_step": "user clicks the login button",
"similarity": 1.0,
"message": "Exact step match found. Do NOT create a new step."
}
check_ast_duplicate
Structural comparison of .spec.ts files using tree-sitter AST fingerprinting.
Inputs:
| Field | Type | Description |
|---|---|---|
spec_source | string | TypeScript source of the proposed spec |
spec_filename | string | Intended filename |
Output:
{
"decision": "block",
"allowed": false,
"matches": [
{ "file": "login.spec.ts", "similarity": 0.94, "decision": "block" }
],
"message": "BLOCKED: 'new.spec.ts' duplicates existing test logic..."
}
Decision thresholds:
| Similarity | Decision |
|---|---|
| β₯ 0.90 | block β creation refused |
| 0.75β0.90 | warn β review recommended |
| < 0.75 | allow β safe to create |
validate_file_creation
Final gate before any file write. Validates directory, extension, naming convention, and uniqueness.
Inputs:
| Field | Type | Description |
|---|---|---|
target_directory | string | One of: features, steps, tests |
filename | string | Proposed filename with extension |
Output:
{
"allowed": true,
"reason": "All checks passed. 'checkout.feature' can be created in 'features'.",
"checks": [
"PASS: Extension is not globally blocked.",
"PASS: Directory 'features' is allowed.",
"PASS: Extension is allowed in 'features'.",
"PASS: Naming convention satisfied.",
"PASS: No duplicate filename found."
]
}
validate_test_structure
Checks that all three BDD artefacts exist for a given feature name.
Inputs:
| Field | Type | Description |
|---|---|---|
feature_name | string | Snake-case feature name (e.g. user_login) |
Output:
{
"complete": false,
"missing": ["spec"],
"present": ["feature", "steps"],
"expected_files": {
"feature": "playwright-project/features/user_login.feature",
"steps": "playwright-project/steps/user_login_steps.ts",
"spec": "playwright-project/tests/user_login.spec.ts"
},
"message": "Incomplete test structure for 'user_login'. Missing: ['spec']."
}
parse_user_story_intent
Converts a plain-English user story into a structured test intent and checks the registry for duplicates.
Inputs:
| Field | Type | Description |
|---|---|---|
user_story | string | Plain-English story |
jira_id | string | Optional JIRA ID (e.g. QA-123) |
register | bool | Save to registry if true |
Output:
{
"feature": "login",
"scenario": "login_valid_credentials",
"test_name": "TC_login_valid_credentials",
"jira_id": "QA-42",
"valid": true,
"duplicate": false,
"message": "Intent parsed successfully."
}
How the Registry Works
registry/test_registry.json stores a mapping of JIRA tickets to test artefacts:
{
"version": "1.0",
"mappings": {
"QA-42": {
"feature": "login",
"test_name": "TC_login_valid_credentials"
}
}
}
parse_user_story_intentwithregister=truewrites to this file.validate_file_creationreads it to block duplicate filenames.- The registry is append-only β existing entries are never overwritten.
Governance Rules
| Rule | Enforced by |
|---|---|
No duplicate .feature files | check_feature_duplicate |
| No duplicate step definitions | find_existing_step |
| No duplicate spec logic | check_ast_duplicate |
Only features/, steps/, tests/ directories | validate_file_creation |
No .md or .txt files | validate_file_creation |
snake_case.feature naming | validate_file_creation |
snake_case_steps.ts naming | validate_file_creation |
snake_case.spec.ts naming | validate_file_creation |
TC_feature_scenario test names | parse_user_story_intent |
| Complete 3-file BDD structure | validate_test_structure |
| No duplicate JIRA/business logic | parse_user_story_intent |
Extending the Server
Adding a new tool
- Create
tools/my_tool.pywith the business logic function. - Import and register in
server.py:
from tools.my_tool import my_function
@mcp.tool()
def my_tool_name(param: str) -> dict:
"""Docstring shown to the AI agent."""
return my_function(param)
Adding new rules
Add rule functions to config/rules.py following the (bool, str) return convention, then call them from the relevant tool.
Adjusting thresholds
Edit config/settings.py or set environment variables β no code changes needed.
Logging
All tool decisions are appended to logs/mcp.log:
2025-01-01 12:00:01 INFO qa_mcp.server β TOOL check_feature_duplicate called β file='checkout.feature'
2025-01-01 12:00:01 WARNING qa_mcp.tools.feature_duplicate β Duplicate feature detected: 'checkout.feature' ~ 'features/cart_checkout.feature' (similarity=0.912)
2025-01-01 12:00:01 INFO qa_mcp.server β check_feature_duplicate β allowed=False status=duplicate
Log levels: DEBUG (file only) Β· INFO Β· WARNING Β· ERROR (file + console).
