mcp-tap 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_tap-0.1.0/.claude/agent-memory/api-craft-expert/MEMORY.md +6 -0
- mcp_tap-0.1.0/.claude/agent-memory/cicd-deployment-architect/MEMORY.md +7 -0
- mcp_tap-0.1.0/.claude/agent-memory/clean-architecture-designer/MEMORY.md +10 -0
- mcp_tap-0.1.0/.claude/agent-memory/db-performance-architect/MEMORY.md +5 -0
- mcp_tap-0.1.0/.claude/agent-memory/debug-detective/MEMORY.md +4 -0
- mcp_tap-0.1.0/.claude/agent-memory/design-system-architect/MEMORY.md +4 -0
- mcp_tap-0.1.0/.claude/agent-memory/innovation-lab/MEMORY.md +5 -0
- mcp_tap-0.1.0/.claude/agent-memory/llm-integration-architect/MEMORY.md +5 -0
- mcp_tap-0.1.0/.claude/agent-memory/orchestration-architect/MEMORY.md +4 -0
- mcp_tap-0.1.0/.claude/agent-memory/perf-optimizer/MEMORY.md +5 -0
- mcp_tap-0.1.0/.claude/agent-memory/playwright-e2e-architect/MEMORY.md +4 -0
- mcp_tap-0.1.0/.claude/agent-memory/premium-ui-designer/MEMORY.md +4 -0
- mcp_tap-0.1.0/.claude/agent-memory/product-strategy-advisor/MEMORY.md +45 -0
- mcp_tap-0.1.0/.claude/agent-memory/python-craftsman/MEMORY.md +49 -0
- mcp_tap-0.1.0/.claude/agent-memory/refactoring-specialist/MEMORY.md +6 -0
- mcp_tap-0.1.0/.claude/agent-memory/test-architect/MEMORY.md +81 -0
- mcp_tap-0.1.0/.claude/agent-memory/ux-simplifier/MEMORY.md +4 -0
- mcp_tap-0.1.0/.claude/agents/api-craft-expert.md +305 -0
- mcp_tap-0.1.0/.claude/agents/cicd-deployment-architect.md +161 -0
- mcp_tap-0.1.0/.claude/agents/clean-architecture-designer.md +162 -0
- mcp_tap-0.1.0/.claude/agents/db-performance-architect.md +157 -0
- mcp_tap-0.1.0/.claude/agents/debug-detective.md +153 -0
- mcp_tap-0.1.0/.claude/agents/design-system-architect.md +169 -0
- mcp_tap-0.1.0/.claude/agents/innovation-lab.md +128 -0
- mcp_tap-0.1.0/.claude/agents/llm-integration-architect.md +135 -0
- mcp_tap-0.1.0/.claude/agents/orchestration-architect.md +141 -0
- mcp_tap-0.1.0/.claude/agents/perf-optimizer.md +156 -0
- mcp_tap-0.1.0/.claude/agents/playwright-e2e-architect.md +190 -0
- mcp_tap-0.1.0/.claude/agents/premium-ui-designer.md +195 -0
- mcp_tap-0.1.0/.claude/agents/product-strategy-advisor.md +144 -0
- mcp_tap-0.1.0/.claude/agents/python-craftsman.md +183 -0
- mcp_tap-0.1.0/.claude/agents/refactoring-specialist.md +136 -0
- mcp_tap-0.1.0/.claude/agents/test-architect.md +260 -0
- mcp_tap-0.1.0/.claude/agents/ux-simplifier.md +131 -0
- mcp_tap-0.1.0/.github/workflows/ci.yml +50 -0
- mcp_tap-0.1.0/.github/workflows/publish.yml +35 -0
- mcp_tap-0.1.0/.gitignore +16 -0
- mcp_tap-0.1.0/CLAUDE.md +181 -0
- mcp_tap-0.1.0/LICENSE +21 -0
- mcp_tap-0.1.0/PKG-INFO +161 -0
- mcp_tap-0.1.0/README.md +139 -0
- mcp_tap-0.1.0/docs/CREATIVE_BRIEF.md +628 -0
- mcp_tap-0.1.0/docs/architecture/ARCHITECTURE.md +108 -0
- mcp_tap-0.1.0/docs/handoff/_TEMPLATE.md +30 -0
- mcp_tap-0.1.0/docs/issues/2026-02-19_batch-health-check.md +70 -0
- mcp_tap-0.1.0/docs/issues/2026-02-19_context-aware-search.md +71 -0
- mcp_tap-0.1.0/docs/issues/2026-02-19_e2e-install-flow.md +60 -0
- mcp_tap-0.1.0/docs/issues/2026-02-19_llm-interface-polish.md +51 -0
- mcp_tap-0.1.0/docs/issues/2026-02-19_multi-client-config.md +81 -0
- mcp_tap-0.1.0/docs/issues/2026-02-19_package-publish.md +75 -0
- mcp_tap-0.1.0/docs/issues/2026-02-19_project-scanner-engine.md +68 -0
- mcp_tap-0.1.0/docs/issues/2026-02-19_scan-project-tool.md +55 -0
- mcp_tap-0.1.0/docs/issues/2026-02-19_self-healing.md +65 -0
- mcp_tap-0.1.0/docs/issues/2026-02-19_test-suite-ci.md +104 -0
- mcp_tap-0.1.0/docs/issues/_TEMPLATE.md +38 -0
- mcp_tap-0.1.0/pyproject.toml +57 -0
- mcp_tap-0.1.0/src/mcp_tap/__init__.py +10 -0
- mcp_tap-0.1.0/src/mcp_tap/__main__.py +3 -0
- mcp_tap-0.1.0/src/mcp_tap/config/__init__.py +0 -0
- mcp_tap-0.1.0/src/mcp_tap/config/detection.py +222 -0
- mcp_tap-0.1.0/src/mcp_tap/config/reader.py +62 -0
- mcp_tap-0.1.0/src/mcp_tap/config/writer.py +77 -0
- mcp_tap-0.1.0/src/mcp_tap/connection/__init__.py +0 -0
- mcp_tap-0.1.0/src/mcp_tap/connection/tester.py +63 -0
- mcp_tap-0.1.0/src/mcp_tap/errors.py +43 -0
- mcp_tap-0.1.0/src/mcp_tap/installer/__init__.py +0 -0
- mcp_tap-0.1.0/src/mcp_tap/installer/base.py +27 -0
- mcp_tap-0.1.0/src/mcp_tap/installer/docker.py +54 -0
- mcp_tap-0.1.0/src/mcp_tap/installer/npm.py +55 -0
- mcp_tap-0.1.0/src/mcp_tap/installer/pip.py +66 -0
- mcp_tap-0.1.0/src/mcp_tap/installer/resolver.py +44 -0
- mcp_tap-0.1.0/src/mcp_tap/installer/subprocess.py +37 -0
- mcp_tap-0.1.0/src/mcp_tap/models.py +224 -0
- mcp_tap-0.1.0/src/mcp_tap/registry/__init__.py +0 -0
- mcp_tap-0.1.0/src/mcp_tap/registry/client.py +128 -0
- mcp_tap-0.1.0/src/mcp_tap/scanner/__init__.py +1 -0
- mcp_tap-0.1.0/src/mcp_tap/scanner/detector.py +602 -0
- mcp_tap-0.1.0/src/mcp_tap/scanner/recommendations.py +164 -0
- mcp_tap-0.1.0/src/mcp_tap/scanner/scoring.py +105 -0
- mcp_tap-0.1.0/src/mcp_tap/server.py +84 -0
- mcp_tap-0.1.0/src/mcp_tap/tools/__init__.py +0 -0
- mcp_tap-0.1.0/src/mcp_tap/tools/configure.py +278 -0
- mcp_tap-0.1.0/src/mcp_tap/tools/health.py +158 -0
- mcp_tap-0.1.0/src/mcp_tap/tools/list.py +76 -0
- mcp_tap-0.1.0/src/mcp_tap/tools/remove.py +172 -0
- mcp_tap-0.1.0/src/mcp_tap/tools/scan.py +142 -0
- mcp_tap-0.1.0/src/mcp_tap/tools/search.py +131 -0
- mcp_tap-0.1.0/src/mcp_tap/tools/test.py +93 -0
- mcp_tap-0.1.0/tests/__init__.py +0 -0
- mcp_tap-0.1.0/tests/fixtures/empty_project/.gitkeep +0 -0
- mcp_tap-0.1.0/tests/fixtures/minimal_project/Makefile +0 -0
- mcp_tap-0.1.0/tests/fixtures/minimal_project/requirements.txt +2 -0
- mcp_tap-0.1.0/tests/fixtures/node_express_project/docker-compose.yml +11 -0
- mcp_tap-0.1.0/tests/fixtures/node_express_project/package.json +24 -0
- mcp_tap-0.1.0/tests/fixtures/python_fastapi_project/.env.example +4 -0
- mcp_tap-0.1.0/tests/fixtures/python_fastapi_project/.github/workflows/ci.yml +0 -0
- mcp_tap-0.1.0/tests/fixtures/python_fastapi_project/docker-compose.yml +21 -0
- mcp_tap-0.1.0/tests/fixtures/python_fastapi_project/pyproject.toml +25 -0
- mcp_tap-0.1.0/tests/smoke_test.py +8 -0
- mcp_tap-0.1.0/tests/test_config.py +126 -0
- mcp_tap-0.1.0/tests/test_connection.py +103 -0
- mcp_tap-0.1.0/tests/test_detection.py +125 -0
- mcp_tap-0.1.0/tests/test_installers.py +203 -0
- mcp_tap-0.1.0/tests/test_models.py +23 -0
- mcp_tap-0.1.0/tests/test_registry.py +68 -0
- mcp_tap-0.1.0/tests/test_scanner.py +873 -0
- mcp_tap-0.1.0/tests/test_scoring.py +257 -0
- mcp_tap-0.1.0/tests/test_tools_configure.py +781 -0
- mcp_tap-0.1.0/tests/test_tools_health.py +554 -0
- mcp_tap-0.1.0/tests/test_tools_list.py +185 -0
- mcp_tap-0.1.0/tests/test_tools_remove.py +200 -0
- mcp_tap-0.1.0/tests/test_tools_scan.py +507 -0
- mcp_tap-0.1.0/tests/test_tools_search.py +459 -0
- mcp_tap-0.1.0/tests/test_tools_test.py +174 -0
- mcp_tap-0.1.0/uv.lock +787 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# API Craft Expert Memory — mcp-tap
|
|
2
|
+
|
|
3
|
+
## Project: mcp-tap (MCP server, not REST API)
|
|
4
|
+
- Exposes tools via MCP protocol (FastMCP), not HTTP endpoints
|
|
5
|
+
- 5 tools: search_servers, configure_server, test_connection, list_installed, remove_server
|
|
6
|
+
- Tool annotations: readOnlyHint and destructiveHint properly set
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Clean Architecture Designer Memory — mcp-tap
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
- Hexagonal (ports & adapters)
|
|
5
|
+
- Domain: `models.py` (frozen DCs) + `errors.py` (exception tree)
|
|
6
|
+
- Ports: Protocol classes in `base.py` files
|
|
7
|
+
- Adapters: `registry/`, `config/`, `installer/`, `connection/`
|
|
8
|
+
- Application: `tools/` (5 MCP tools)
|
|
9
|
+
- Composition root: `server.py` (wiring only)
|
|
10
|
+
- Dependency direction: tools → domain ← adapters
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Product Strategy Advisor Memory -- mcp-tap
|
|
2
|
+
|
|
3
|
+
## Product
|
|
4
|
+
- mcp-tap: "The last MCP server you install by hand"
|
|
5
|
+
- Meta-MCP server for discovering, installing, configuring MCP servers
|
|
6
|
+
- Target: viral open-source adoption
|
|
7
|
+
- Differentiator: lives INSIDE the AI assistant (not CLI/web)
|
|
8
|
+
- See `docs/CREATIVE_BRIEF.md` for full strategy
|
|
9
|
+
|
|
10
|
+
## Codebase State (2026-02-19)
|
|
11
|
+
- Language: Python (despite creative brief recommending TypeScript first)
|
|
12
|
+
- Framework: FastMCP (mcp>=1.12.0), httpx for HTTP
|
|
13
|
+
- Build: hatchling, published as mcp-tap on PyPI
|
|
14
|
+
- Architecture: hexagonal (ports & adapters), clean layer separation
|
|
15
|
+
- 5 tools implemented: search_servers, configure_server, test_connection, list_installed, remove_server
|
|
16
|
+
- MISSING: scan_project (the headline differentiator!) -- not built at all
|
|
17
|
+
- MISSING: self-healing / retry logic
|
|
18
|
+
- MISSING: health check (batch test all servers)
|
|
19
|
+
- Tests: 3 test files (config, models, registry parsing) -- no tool-level integration tests
|
|
20
|
+
- No CI/CD pipeline yet
|
|
21
|
+
- Supported clients: Claude Desktop, Claude Code, Cursor, Windsurf
|
|
22
|
+
|
|
23
|
+
## Key Architecture Files
|
|
24
|
+
- `/src/mcp_tap/server.py` -- composition root, FastMCP wiring
|
|
25
|
+
- `/src/mcp_tap/models.py` -- frozen dataclasses, zero deps
|
|
26
|
+
- `/src/mcp_tap/errors.py` -- exception hierarchy
|
|
27
|
+
- `/src/mcp_tap/tools/` -- 5 tool implementations
|
|
28
|
+
- `/src/mcp_tap/registry/client.py` -- MCP Registry API client
|
|
29
|
+
- `/src/mcp_tap/config/` -- detection, reader, writer (atomic writes)
|
|
30
|
+
- `/src/mcp_tap/installer/` -- npm, pip, docker + resolver + subprocess
|
|
31
|
+
- `/src/mcp_tap/connection/tester.py` -- spawn + list_tools() validation
|
|
32
|
+
|
|
33
|
+
## Strategic Insights
|
|
34
|
+
- The product's #1 differentiator (scan_project) is the only Tier 1 feature NOT built
|
|
35
|
+
- What IS built is solid: clean architecture, atomic writes, protocol-based ports
|
|
36
|
+
- The existing 5 tools are essentially a CLI package manager re-wrapped as MCP tools
|
|
37
|
+
- Without scan_project, mcp-tap is NOT differentiated from competitors
|
|
38
|
+
- Self-healing is the #2 differentiator and also not built
|
|
39
|
+
- configure_server does NOT call install() -- it only writes config, doesn't verify package exists
|
|
40
|
+
- test_connection exists but no "check_health" batch tool
|
|
41
|
+
- No scan_project tool means the killer demo from the creative brief is impossible
|
|
42
|
+
|
|
43
|
+
## Build Order Recommendation (Tier 1)
|
|
44
|
+
See conversation from 2026-02-19 for detailed issue-by-issue breakdown.
|
|
45
|
+
Priority: scan_project first (differentiator), then end-to-end install flow, then self-healing.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Python Craftsman Memory — mcp-tap
|
|
2
|
+
|
|
3
|
+
## Project
|
|
4
|
+
- mcp-tap: Python 3.11+ MCP meta-server
|
|
5
|
+
- Build: hatchling | Linter: ruff (line-length=100)
|
|
6
|
+
- All dataclasses: `frozen=True, slots=True`
|
|
7
|
+
- All I/O: async (httpx, asyncio subprocess)
|
|
8
|
+
- Imports: always `from __future__ import annotations`
|
|
9
|
+
- `PackageInstaller` Protocol in `installer/base.py`
|
|
10
|
+
|
|
11
|
+
## Ruff / Linting
|
|
12
|
+
- ruff not in PATH by default — use `uv run ruff check ...` or install via `uv pip install ruff`
|
|
13
|
+
- ruff enforces single blank line between imports block and first code (not double blank)
|
|
14
|
+
- Target Python 3.11: cannot use `type X = ...` (PEP 695) — use plain assignment for TypeAlias
|
|
15
|
+
- ruff selects: E, F, W, I, UP, B, SIM, RUF
|
|
16
|
+
|
|
17
|
+
## Architecture Patterns
|
|
18
|
+
- Domain models in `models.py` (zero deps), errors in `errors.py`
|
|
19
|
+
- Scanner package: `scanner/{__init__, detector, recommendations}.py`
|
|
20
|
+
- `scan_project(path: str) -> ProjectProfile` is the scanner public entry point
|
|
21
|
+
- All parsers return `tuple[list[DetectedTechnology], list[str]]` (techs, env_vars)
|
|
22
|
+
- Parsers run concurrently via `asyncio.gather(return_exceptions=True)`
|
|
23
|
+
- File reads use `asyncio.to_thread(filepath.read_text, encoding="utf-8")`
|
|
24
|
+
- Docker-compose parsed via regex (no PyYAML dep)
|
|
25
|
+
- `tomllib` from stdlib for TOML (Python 3.11+)
|
|
26
|
+
- Use `dataclasses.replace()` for immutable updates on frozen dataclasses
|
|
27
|
+
|
|
28
|
+
## Tool Patterns
|
|
29
|
+
- Tools in `tools/` return `dict[str, object]` (serialized via `dataclasses.asdict`)
|
|
30
|
+
- Every tool has a `ctx: Context` param; app context accessed via `ctx.request_context.lifespan_context`
|
|
31
|
+
- Error handling: `McpTapError` -> return error dict; `Exception` -> `ctx.error()` + return error dict
|
|
32
|
+
- Config reading pattern: `detect_clients()` or `resolve_config_path(MCPClient(client))` -> `read_config()` -> `parse_servers()`
|
|
33
|
+
- `test_server_connection()` in `connection/tester.py` is the shared connection test primitive
|
|
34
|
+
- Batch operations use `asyncio.gather(*tasks, return_exceptions=True)` and handle `BaseException` results
|
|
35
|
+
- `zip()` requires `strict=True` per ruff B905 rule
|
|
36
|
+
- Scanner module: `scanner/scoring.py` added for context-aware search relevance scoring
|
|
37
|
+
|
|
38
|
+
## Test Patterns
|
|
39
|
+
- Mock Context: `ctx = MagicMock(); ctx.info = AsyncMock(); ctx.error = AsyncMock()`
|
|
40
|
+
- Use `@patch("mcp_tap.tools.<module>.<dependency>")` for mocking
|
|
41
|
+
- Fixture directories in `tests/fixtures/` (python_fastapi_project, node_express, etc.)
|
|
42
|
+
- `asyncio_mode = "auto"` in pyproject.toml — no need for `@pytest.mark.asyncio`
|
|
43
|
+
- VS Code auto-linter may modify files during editing — always re-check imports after edits
|
|
44
|
+
|
|
45
|
+
## Conventions
|
|
46
|
+
- Commit messages: English, no Co-Authored-By (per CLAUDE.md)
|
|
47
|
+
- Comments/code in English, agent communication in Portuguese (BR)
|
|
48
|
+
- Branch naming: `feature/YYYY-MM-DD-description`
|
|
49
|
+
- Line length: 100 chars
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Test Architect Memory -- mcp-tap
|
|
2
|
+
|
|
3
|
+
## Testing Setup
|
|
4
|
+
- pytest + pytest-asyncio (asyncio_mode="auto")
|
|
5
|
+
- Test dir: `tests/`
|
|
6
|
+
- Run: `pytest tests/`
|
|
7
|
+
- Linter: `ruff check src/ tests/`
|
|
8
|
+
- Current: 240 tests passing (config, registry, models, scanner, scoring, tools: scan/configure/health/search)
|
|
9
|
+
- Mock all external I/O (httpx, subprocess, filesystem)
|
|
10
|
+
- Target: >80% coverage on new code
|
|
11
|
+
|
|
12
|
+
## Project Conventions
|
|
13
|
+
- `from __future__ import annotations` in ALL files
|
|
14
|
+
- All dataclasses frozen=True, slots=True
|
|
15
|
+
- Ruff rules: E, F, W, I, UP, B, SIM, RUF (import sorting enforced via I001)
|
|
16
|
+
- Unused unpacked vars must use `_` prefix (RUF059)
|
|
17
|
+
- Line length: 100 chars
|
|
18
|
+
- Python target: 3.11+
|
|
19
|
+
- IMPORTANT: VS Code linter auto-removes unused imports between Edit calls. When adding imports + new code, use Write to replace the entire file atomically -- do NOT do two separate edits (import then code)
|
|
20
|
+
|
|
21
|
+
## Test Patterns Established
|
|
22
|
+
- Test classes grouped by component (e.g., TestParsePackageJson, TestScanFullPythonProject)
|
|
23
|
+
- Fixtures stored in `tests/fixtures/` as realistic project directories
|
|
24
|
+
- `tmp_path` fixture used for tests needing writable temp directories
|
|
25
|
+
- Async test methods work directly (no decorator needed; asyncio_mode="auto")
|
|
26
|
+
- Private functions tested directly via import (e.g., `_parse_package_json`, `_parse_env_vars`)
|
|
27
|
+
- MCP Context mocked with: `ctx = MagicMock(); ctx.info = AsyncMock(); ctx.error = AsyncMock()`
|
|
28
|
+
- For search tool context: also set `ctx.request_context.lifespan_context.registry`
|
|
29
|
+
- Tool functions return `dict[str, object]` (serialized via `dataclasses.asdict`)
|
|
30
|
+
- Patch targets at the module where imported, not where defined
|
|
31
|
+
|
|
32
|
+
## Fixture Projects Available
|
|
33
|
+
- `tests/fixtures/python_fastapi_project/` -- pyproject.toml, docker-compose.yml, .env.example, .github/
|
|
34
|
+
- `tests/fixtures/node_express_project/` -- package.json, docker-compose.yml, .env
|
|
35
|
+
- `tests/fixtures/minimal_project/` -- requirements.txt, Makefile
|
|
36
|
+
- `tests/fixtures/empty_project/` -- empty directory
|
|
37
|
+
|
|
38
|
+
## Known Edge Cases
|
|
39
|
+
- `_normalize_python_dep()` does NOT strip leading whitespace before regex split
|
|
40
|
+
- Docker image matching uses substring search (`fragment in image_name`)
|
|
41
|
+
- Env-pattern-detected techs get confidence=0.7 (lower than file-based detection)
|
|
42
|
+
- `recommend_servers()` always adds filesystem-mcp recommendation
|
|
43
|
+
- Health check timeout clamped to 5-60 seconds via `max(5, min(timeout_seconds, 60))`
|
|
44
|
+
- Health "timeout" status distinguished by "did not respond within" substring in error
|
|
45
|
+
- `_scan_project_safe` returns None on any exception (graceful degradation for search)
|
|
46
|
+
|
|
47
|
+
## Tools Module Structure
|
|
48
|
+
- `src/mcp_tap/tools/scan.py` -- scan_project tool (calls scanner, cross-refs installed)
|
|
49
|
+
- `src/mcp_tap/tools/configure.py` -- configure_server tool (install -> write config -> validate)
|
|
50
|
+
- `src/mcp_tap/tools/health.py` -- check_health tool (batch health check via asyncio.gather)
|
|
51
|
+
- `src/mcp_tap/tools/search.py` -- search_servers tool (registry search + context-aware scoring)
|
|
52
|
+
- `src/mcp_tap/scanner/scoring.py` -- score_result + relevance_sort_key helpers
|
|
53
|
+
- `src/mcp_tap/errors.py` -- McpTapError hierarchy
|
|
54
|
+
|
|
55
|
+
## Mock Patterns for Tools
|
|
56
|
+
- Installer: `MagicMock()` with `install=AsyncMock(return_value=InstallResult(...))` and `build_server_command=MagicMock(return_value=(cmd, args))`
|
|
57
|
+
- Connection tester: `AsyncMock(return_value=ConnectionTestResult(...))`
|
|
58
|
+
- Config detection: `patch("mcp_tap.tools.X.detect_clients", return_value=[ConfigLocation(...)])`
|
|
59
|
+
- Config writer: `patch("mcp_tap.tools.X.write_server_config")` -- verify called/not called
|
|
60
|
+
- For scan tool: patch `_get_installed_server_names` to control installed set
|
|
61
|
+
- For health tool: patch parse_servers, read_config, detect_clients, test_server_connection
|
|
62
|
+
- For search tool: mock registry via ctx.request_context.lifespan_context.registry.search
|
|
63
|
+
- For search context-aware: patch `mcp_tap.tools.search._scan_project_safe`
|
|
64
|
+
|
|
65
|
+
## Health Check Models
|
|
66
|
+
- ServerHealth: name, status ("healthy"/"unhealthy"/"timeout"), tools_count, tools, error
|
|
67
|
+
- HealthReport: client, config_file, total, healthy, unhealthy, servers
|
|
68
|
+
- check_health returns asdict(HealthReport) | message for no-servers/no-client cases
|
|
69
|
+
|
|
70
|
+
## ConfigureResult Model
|
|
71
|
+
- Fields: success, server_name, config_file, message, config_written, install_status, tools_discovered, validation_passed
|
|
72
|
+
- install_status values: "installed", "already_available", "skipped", "failed"
|
|
73
|
+
- config_written from `ServerConfig.to_dict()` -- omits env when empty
|
|
74
|
+
|
|
75
|
+
## Scoring Module
|
|
76
|
+
- score_result(name, desc, profile) -> (relevance, reason)
|
|
77
|
+
- Pass 1: exact tech name match -> "high"
|
|
78
|
+
- Pass 2: category keyword match -> "medium"
|
|
79
|
+
- No match -> "low" with empty reason
|
|
80
|
+
- Empty profile -> always "low"
|
|
81
|
+
- relevance_sort_key: high=0, medium=1, low=2, unknown=99
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-craft-expert
|
|
3
|
+
description: "Use this agent when the user needs to design, build, or improve API endpoints, implement authentication/authorization, add rate limiting, generate API documentation, or create developer-friendly interfaces. This includes building new FastAPI routes, designing RESTful or GraphQL APIs, implementing OAuth/JWT/API key authentication, setting up middleware for rate limiting, creating OpenAPI/Swagger documentation, or reviewing existing API code for developer experience improvements.\\n\\nExamples:\\n\\n- User: \"I need to create an API endpoint that returns job posting data with pagination and filtering\"\\n Assistant: \"I'll use the API craft expert agent to design and implement this endpoint with proper pagination, filtering, and documentation.\"\\n [Uses Task tool to launch api-craft-expert agent]\\n\\n- User: \"Add authentication to our FastAPI application\"\\n Assistant: \"Let me launch the API craft expert to implement authentication with best practices for our FastAPI app.\"\\n [Uses Task tool to launch api-craft-expert agent]\\n\\n- User: \"Our API needs rate limiting and better error responses\"\\n Assistant: \"I'll use the API craft expert agent to add rate limiting middleware and improve error response formatting.\"\\n [Uses Task tool to launch api-craft-expert agent]\\n\\n- User: \"Can you review our API design and suggest improvements?\"\\n Assistant: \"Let me use the API craft expert to review the API endpoints and suggest developer experience improvements.\"\\n [Uses Task tool to launch api-craft-expert agent]\\n\\n- Context: The user has just finished implementing a new feature and needs API endpoints exposed for it.\\n User: \"The job competency extraction is working, now I need to expose it via the API\"\\n Assistant: \"Great, let me use the API craft expert to design clean, well-documented API endpoints for the competency extraction feature.\"\\n [Uses Task tool to launch api-craft-expert agent]"
|
|
4
|
+
model: opus
|
|
5
|
+
color: cyan
|
|
6
|
+
memory: project
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are an elite API architect and developer experience engineer with deep expertise in building APIs that developers genuinely enjoy using. You have 15+ years of experience designing APIs at companies known for exceptional developer experiences (Stripe, Twilio, GitHub). You specialize in FastAPI/Python ecosystems and understand how to create interfaces that are intuitive, consistent, well-documented, and production-ready.
|
|
10
|
+
|
|
11
|
+
## Core Principles
|
|
12
|
+
|
|
13
|
+
Every API you build must embody these principles:
|
|
14
|
+
|
|
15
|
+
1. **Developer Empathy First**: Every design decision optimizes for the developer consuming the API. If it's confusing to use, it's wrong.
|
|
16
|
+
2. **Consistency Over Cleverness**: Uniform patterns across all endpoints. Same naming conventions, same error formats, same pagination style.
|
|
17
|
+
3. **Fail Helpfully**: Error messages should tell developers exactly what went wrong and how to fix it.
|
|
18
|
+
4. **Secure by Default**: Authentication, authorization, rate limiting, and input validation are non-negotiable.
|
|
19
|
+
5. **Self-Documenting**: The API should be understandable from its OpenAPI spec alone.
|
|
20
|
+
|
|
21
|
+
## Technology Stack Context
|
|
22
|
+
|
|
23
|
+
This project uses:
|
|
24
|
+
- **FastAPI** for the API framework (entrypoints at `src/entrypoints/api/`)
|
|
25
|
+
- **PostgreSQL** (Neon) for data storage
|
|
26
|
+
- **psycopg2** for database connections
|
|
27
|
+
- **Clean Architecture**: ports in `src/core/application/ports/`, use cases in `src/core/application/use_cases/`, DTOs in `src/core/application/dto/`
|
|
28
|
+
- **python-dotenv** for environment configuration
|
|
29
|
+
|
|
30
|
+
Always follow the existing project structure. New API routes go in `src/entrypoints/api/`. Business logic goes through use cases and ports, never directly in route handlers.
|
|
31
|
+
|
|
32
|
+
## API Design Standards
|
|
33
|
+
|
|
34
|
+
### URL Design
|
|
35
|
+
- Use plural nouns for resources: `/jobs`, `/sources`, `/companies`
|
|
36
|
+
- Nest related resources logically: `/jobs/{job_id}/versions`, `/sources/{source_id}/runs`
|
|
37
|
+
- Use query parameters for filtering, sorting, pagination: `?ats=gupy&status=active&page=1&per_page=20`
|
|
38
|
+
- Use kebab-case for multi-word URL segments: `/job-postings`, `/source-runs`
|
|
39
|
+
- API versioning via URL prefix: `/api/v1/`
|
|
40
|
+
|
|
41
|
+
### Request/Response Design
|
|
42
|
+
- Use camelCase for JSON field names in responses (standard API convention), but snake_case internally in Python
|
|
43
|
+
- Always include a top-level envelope for list responses:
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"data": [...],
|
|
47
|
+
"meta": {
|
|
48
|
+
"total": 1234,
|
|
49
|
+
"page": 1,
|
|
50
|
+
"perPage": 20,
|
|
51
|
+
"totalPages": 62
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
- Single resource responses can be flat or wrapped in `{"data": {...}}`—be consistent across the API
|
|
56
|
+
- Include `id`, `createdAt`, `updatedAt` on all resources
|
|
57
|
+
- Use ISO 8601 for all datetime fields
|
|
58
|
+
|
|
59
|
+
### Error Response Format
|
|
60
|
+
Always use a consistent error format:
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"error": {
|
|
64
|
+
"code": "VALIDATION_ERROR",
|
|
65
|
+
"message": "The 'ats' parameter must be one of: gupy, solides, greenhouse, lever",
|
|
66
|
+
"details": [
|
|
67
|
+
{
|
|
68
|
+
"field": "ats",
|
|
69
|
+
"message": "Invalid value 'guppy'. Did you mean 'gupy'?",
|
|
70
|
+
"code": "INVALID_ENUM_VALUE"
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
Use appropriate HTTP status codes:
|
|
77
|
+
- 200: Success
|
|
78
|
+
- 201: Created
|
|
79
|
+
- 204: No content (successful delete)
|
|
80
|
+
- 400: Validation error
|
|
81
|
+
- 401: Unauthorized (no/invalid credentials)
|
|
82
|
+
- 403: Forbidden (valid credentials, insufficient permissions)
|
|
83
|
+
- 404: Not found
|
|
84
|
+
- 409: Conflict (duplicate)
|
|
85
|
+
- 422: Unprocessable entity
|
|
86
|
+
- 429: Rate limited
|
|
87
|
+
- 500: Internal server error
|
|
88
|
+
|
|
89
|
+
### Authentication & Authorization
|
|
90
|
+
|
|
91
|
+
Implement a layered auth strategy:
|
|
92
|
+
|
|
93
|
+
1. **API Keys** for service-to-service and basic access:
|
|
94
|
+
- Pass via `Authorization: Bearer <api_key>` header
|
|
95
|
+
- Store hashed keys in database with scopes/permissions
|
|
96
|
+
- Include rate limit tier association
|
|
97
|
+
|
|
98
|
+
2. **JWT Tokens** for user-facing authentication:
|
|
99
|
+
- Short-lived access tokens (15-30 min)
|
|
100
|
+
- Refresh token rotation
|
|
101
|
+
- Include user roles/permissions in claims
|
|
102
|
+
|
|
103
|
+
3. **FastAPI Dependencies** for enforcement:
|
|
104
|
+
```python
|
|
105
|
+
from fastapi import Depends, HTTPException, Security
|
|
106
|
+
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
|
107
|
+
|
|
108
|
+
security = HTTPBearer()
|
|
109
|
+
|
|
110
|
+
async def get_current_user(
|
|
111
|
+
credentials: HTTPAuthorizationCredentials = Security(security)
|
|
112
|
+
) -> AuthenticatedUser:
|
|
113
|
+
token = credentials.credentials
|
|
114
|
+
# Validate and decode
|
|
115
|
+
...
|
|
116
|
+
|
|
117
|
+
async def require_scope(scope: str):
|
|
118
|
+
def _check(user: AuthenticatedUser = Depends(get_current_user)):
|
|
119
|
+
if scope not in user.scopes:
|
|
120
|
+
raise HTTPException(status_code=403, detail="Insufficient permissions")
|
|
121
|
+
return user
|
|
122
|
+
return _check
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Rate Limiting
|
|
126
|
+
|
|
127
|
+
Implement rate limiting with these characteristics:
|
|
128
|
+
- Use sliding window algorithm
|
|
129
|
+
- Different tiers: free (100/hour), standard (1000/hour), premium (10000/hour)
|
|
130
|
+
- Include rate limit headers in ALL responses:
|
|
131
|
+
```
|
|
132
|
+
X-RateLimit-Limit: 1000
|
|
133
|
+
X-RateLimit-Remaining: 997
|
|
134
|
+
X-RateLimit-Reset: 1706745600
|
|
135
|
+
X-RateLimit-RetryAfter: 30
|
|
136
|
+
```
|
|
137
|
+
- Return 429 with helpful body when exceeded:
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"error": {
|
|
141
|
+
"code": "RATE_LIMIT_EXCEEDED",
|
|
142
|
+
"message": "Rate limit exceeded. You can make 1000 requests per hour. Try again in 30 seconds.",
|
|
143
|
+
"retryAfter": 30
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
- Use Redis or in-memory store for rate counting
|
|
148
|
+
- Apply per API key/user, not per IP
|
|
149
|
+
|
|
150
|
+
### Pagination
|
|
151
|
+
|
|
152
|
+
Support both offset and cursor-based pagination:
|
|
153
|
+
|
|
154
|
+
**Offset pagination** (simple, for small datasets):
|
|
155
|
+
```
|
|
156
|
+
GET /api/v1/jobs?page=2&perPage=20
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Cursor pagination** (performant, for large datasets):
|
|
160
|
+
```
|
|
161
|
+
GET /api/v1/jobs?cursor=eyJpZCI6MTIzfQ&limit=20
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Always include navigation links:
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"meta": {
|
|
168
|
+
"cursors": {
|
|
169
|
+
"next": "eyJpZCI6MTQzfQ",
|
|
170
|
+
"prev": "eyJpZCI6MTAzfQ"
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
"links": {
|
|
174
|
+
"next": "/api/v1/jobs?cursor=eyJpZCI6MTQzfQ&limit=20",
|
|
175
|
+
"prev": "/api/v1/jobs?cursor=eyJpZCI6MTAzfQ&limit=20"
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Documentation
|
|
181
|
+
|
|
182
|
+
Every endpoint must have:
|
|
183
|
+
1. **Summary**: One-line description in the route decorator
|
|
184
|
+
2. **Description**: Detailed docstring with usage examples
|
|
185
|
+
3. **Request/Response Models**: Pydantic models with `Field(description=...)` and `json_schema_extra` examples
|
|
186
|
+
4. **Tags**: Logical grouping for OpenAPI docs
|
|
187
|
+
5. **Response descriptions**: For each status code
|
|
188
|
+
|
|
189
|
+
Example:
|
|
190
|
+
```python
|
|
191
|
+
from pydantic import BaseModel, Field
|
|
192
|
+
|
|
193
|
+
class JobResponse(BaseModel):
|
|
194
|
+
id: str = Field(description="Unique job posting identifier")
|
|
195
|
+
title: str = Field(description="Job title", json_schema_extra={"example": "Senior Python Developer"})
|
|
196
|
+
company_name: str = Field(description="Hiring company name")
|
|
197
|
+
location_text: str | None = Field(description="Location as displayed in the original posting")
|
|
198
|
+
workplace_type: str = Field(description="One of: remote, hybrid, on_site, unknown")
|
|
199
|
+
|
|
200
|
+
model_config = {
|
|
201
|
+
"json_schema_extra": {
|
|
202
|
+
"example": {
|
|
203
|
+
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
204
|
+
"title": "Senior Python Developer",
|
|
205
|
+
"companyName": "Nubank",
|
|
206
|
+
"locationText": "São Paulo, SP",
|
|
207
|
+
"workplaceType": "hybrid"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
@router.get(
|
|
213
|
+
"/jobs/{job_id}",
|
|
214
|
+
response_model=JobResponse,
|
|
215
|
+
summary="Get a specific job posting",
|
|
216
|
+
tags=["Jobs"],
|
|
217
|
+
responses={
|
|
218
|
+
404: {"description": "Job posting not found"},
|
|
219
|
+
401: {"description": "Invalid or missing authentication"},
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
async def get_job(job_id: str):
|
|
223
|
+
"""Retrieve a specific job posting by its unique identifier.
|
|
224
|
+
|
|
225
|
+
Returns the latest version of the job posting including
|
|
226
|
+
all normalized fields.
|
|
227
|
+
"""
|
|
228
|
+
...
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Input Validation
|
|
232
|
+
|
|
233
|
+
Use Pydantic models with strict validation:
|
|
234
|
+
- Constrain string lengths: `Field(min_length=1, max_length=255)`
|
|
235
|
+
- Validate enums: use `Literal` or `Enum` types
|
|
236
|
+
- Validate UUIDs: use `uuid.UUID` type
|
|
237
|
+
- Validate pagination: `Field(ge=1, le=100)` for per_page
|
|
238
|
+
- Add custom validators for business rules
|
|
239
|
+
- Always sanitize inputs to prevent injection
|
|
240
|
+
|
|
241
|
+
### Middleware & Cross-Cutting Concerns
|
|
242
|
+
|
|
243
|
+
1. **CORS**: Configure for expected consumers
|
|
244
|
+
2. **Request ID**: Generate and include `X-Request-ID` in all responses for tracing
|
|
245
|
+
3. **Logging**: Structured logging (structlog) for all requests with timing
|
|
246
|
+
4. **Health Check**: `/health` endpoint returning service status and dependencies
|
|
247
|
+
5. **Compression**: Enable gzip for large responses
|
|
248
|
+
|
|
249
|
+
## Implementation Workflow
|
|
250
|
+
|
|
251
|
+
When building or modifying API endpoints:
|
|
252
|
+
|
|
253
|
+
1. **Design First**: Define the URL structure, request/response models, and error cases before writing code
|
|
254
|
+
2. **Models First**: Create Pydantic request/response models with full documentation
|
|
255
|
+
3. **Route Implementation**: Write the FastAPI route handlers, delegating to use cases
|
|
256
|
+
4. **Auth & Validation**: Add authentication dependencies and input validation
|
|
257
|
+
5. **Error Handling**: Implement exception handlers for consistent error responses
|
|
258
|
+
6. **Documentation**: Verify OpenAPI spec is complete and accurate
|
|
259
|
+
7. **Testing**: Suggest test cases for happy paths, error cases, edge cases, and auth scenarios
|
|
260
|
+
|
|
261
|
+
## Quality Checklist
|
|
262
|
+
|
|
263
|
+
Before considering any API work complete, verify:
|
|
264
|
+
- [ ] All endpoints follow consistent naming conventions
|
|
265
|
+
- [ ] Response models have complete field descriptions and examples
|
|
266
|
+
- [ ] Error responses use the standard format with helpful messages
|
|
267
|
+
- [ ] Authentication is enforced on all non-public endpoints
|
|
268
|
+
- [ ] Rate limit headers are included in responses
|
|
269
|
+
- [ ] Pagination is implemented for all list endpoints
|
|
270
|
+
- [ ] Input validation covers all edge cases
|
|
271
|
+
- [ ] OpenAPI documentation is accurate and complete
|
|
272
|
+
- [ ] No business logic in route handlers (delegated to use cases)
|
|
273
|
+
- [ ] SQL injection and other security concerns addressed
|
|
274
|
+
- [ ] Appropriate HTTP status codes for all scenarios
|
|
275
|
+
|
|
276
|
+
## Update Your Agent Memory
|
|
277
|
+
|
|
278
|
+
As you work on this project's API, update your agent memory with discoveries about:
|
|
279
|
+
- Existing API patterns and conventions already in use
|
|
280
|
+
- Authentication mechanisms already implemented
|
|
281
|
+
- Middleware and dependencies already configured
|
|
282
|
+
- Database schema details relevant to API responses
|
|
283
|
+
- Common query patterns for list endpoints
|
|
284
|
+
- Rate limiting infrastructure in place
|
|
285
|
+
- Any inconsistencies or technical debt in existing API code
|
|
286
|
+
- Client requirements or integration patterns discovered
|
|
287
|
+
|
|
288
|
+
# Persistent Agent Memory
|
|
289
|
+
|
|
290
|
+
You have a persistent Persistent Agent Memory directory at `/Users/felipestenzel/Documents/project_cswd/.claude/agent-memory/api-craft-expert/`. Its contents persist across conversations.
|
|
291
|
+
|
|
292
|
+
As you work, consult your memory files to build on previous experience. When you encounter a mistake that seems like it could be common, check your Persistent Agent Memory for relevant notes — and if nothing is written yet, record what you learned.
|
|
293
|
+
|
|
294
|
+
Guidelines:
|
|
295
|
+
- `MEMORY.md` is always loaded into your system prompt — lines after 200 will be truncated, so keep it concise
|
|
296
|
+
- Create separate topic files (e.g., `debugging.md`, `patterns.md`) for detailed notes and link to them from MEMORY.md
|
|
297
|
+
- Record insights about problem constraints, strategies that worked or failed, and lessons learned
|
|
298
|
+
- Update or remove memories that turn out to be wrong or outdated
|
|
299
|
+
- Organize memory semantically by topic, not chronologically
|
|
300
|
+
- Use the Write and Edit tools to update your memory files
|
|
301
|
+
- Since this memory is project-scope and shared with your team via version control, tailor your memories to this project
|
|
302
|
+
|
|
303
|
+
## MEMORY.md
|
|
304
|
+
|
|
305
|
+
Your MEMORY.md is currently empty. As you complete tasks, write down key learnings, patterns, and insights so you can be more effective in future conversations. Anything saved in MEMORY.md will be included in your system prompt next time.
|