{
  "markdown": "<!-- mcp-name: io.github.Codeturion/codesurface -->\n\n# codesurface\n\n[![PyPI Version](https://img.shields.io/pypi/v/codesurface.svg)](https://pypi.org/project/codesurface/)\n[![PyPI Downloads](https://img.shields.io/pypi/dm/codesurface.svg)](https://pypi.org/project/codesurface/)\n[![MCP Registry](https://img.shields.io/badge/MCP-Registry-green)](https://registry.modelcontextprotocol.io/?q=codesurface)\n[![GitHub Stars](https://img.shields.io/github/stars/Codeturion/codesurface)](https://github.com/Codeturion/codesurface)\n[![GitHub Last Commit](https://img.shields.io/github/last-commit/Codeturion/codesurface)](https://github.com/Codeturion/codesurface)\n[![Languages](https://img.shields.io/badge/languages-C%23%20%7C%20C%2B%2B%20%7C%20Go%20%7C%20Java%20%7C%20Python%20%7C%20TS-blueviolet)](https://github.com/Codeturion/codesurface)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n[![Blog Post](https://img.shields.io/badge/Blog-Benchmark%20Write--up-blue)](https://fuatcankoseoglu.com/blog/reducing-llm-agent-hallucinations-through-constrained-api-retrieval)\n\n**MCP server that indexes your codebase's public API at startup and serves it via compact tool responses, saving tokens vs reading source files.**\n\nParses source files, extracts public classes/methods/properties/fields/events, and serves them through 5 MCP tools. Works with Claude Code, Cursor, Windsurf, or any MCP-compatible AI tool.\n\n**Supported languages:** C# (`.cs`), C++ headers (`.h`, `.hpp`, `.hxx`, `.h++`), Go (`.go`), Java (`.java`), Python (`.py`), TypeScript/JavaScript (`.ts`, `.tsx`, `.js`, `.jsx`)\n\n## Quick Start\n\nAdd to your `.mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"codesurface\": {\n      \"command\": \"uvx\",\n      \"args\": [\"codesurface\", \"--project\", \"/path/to/your/src\"]\n    }\n  }\n}\n```\n\nPoint `--project` at any directory containing supported source files (a Unity `Assets/Scripts` folder, a Spring Boot project, a .NET `src/` tree, a Node.js/React project, a Python package, etc.). Languages are auto-detected.\n\nRestart your AI tool and ask: *\"What methods does MyService have?\"*\n\n## CLAUDE.md Snippet\n\nAdd this to your project's `CLAUDE.md` (or equivalent instructions file). **This step is important.** Without it, the AI has the tools but won't know when to reach for them.\n\n````markdown\n## Codebase API Lookup (codesurface MCP)\n\nUse codesurface MCP tools BEFORE Grep, Glob, Read, or Task (subagents) for any class/method/field lookup. This applies to you AND any subagents you spawn.\n\n| Tool | Use when | Example |\n|------|----------|---------|\n| `search` | Find APIs by keyword | `search(\"MergeService\")` |\n| `get_signature` | Need exact signature | `get_signature(\"TryMerge\")` |\n| `get_class` | See all members on a class | `get_class(\"BlastBoardModel\")` |\n| `get_stats` | Codebase overview | `get_stats()` |\n\nEvery result includes file path + line numbers. Use them for targeted reads:\n- `File: Service.cs:32` → `Read(\"Service.cs\", offset=32, limit=15)`\n- `File: Converter.java:504-506` → `Read(\"Converter.java\", offset=504, limit=10)`\n\nNever read a full file when you have a line number. Only fall back to Grep/Read for implementation details (method bodies, control flow).\n````\n\n## Tools\n\n| Tool | Purpose | Example |\n|------|---------|---------|\n| `search` | Find APIs by keyword | \"MergeService\", \"BlastBoard\", \"GridCoord\" |\n| `get_signature` | Exact signature by name or FQN | \"TryMerge\", \"CampGame.Services.IMergeService.TryMerge\" |\n| `get_class` | Full class reference card with all public members | \"BlastBoardModel\" → all methods/fields/properties |\n| `get_stats` | Overview of indexed codebase | File count, record counts, namespace breakdown |\n| `reindex` | Incremental index update (mtime-based) | Only re-parses changed/new/deleted files. Also runs automatically on query misses |\n\n`search`, `get_signature`, and `get_class` accept two optional filters:\n\n- `file_path`: scope results to a directory prefix or exact file (e.g. `\"src/services/\"` or `\"src/services/MergeService.ts\"`)\n- `include_tests`: include test files in results (default `false`). Detects `__tests__/`, `tests/`, `test/`, `*.test.*`, `*.spec.*`, `*_test.*`, `test_*`\n\n## Tested On\n\n| Project | Language | Files | Records | Time |\n|---------|----------|-------|---------|------|\n| [vscode](https://github.com/microsoft/vscode) | TypeScript | 6,611 | 88,293 | 9.3s |\n| [Paper](https://github.com/PaperMC/Paper) | Java | 2,909 | 33,973 | 2.3s |\n| [client-go](https://github.com/kubernetes/client-go) | Go | 219 | 2,760 | 0.4s |\n| [langchain](https://github.com/langchain-ai/langchain) | Python | 1,880 | 12,418 | 1.1s |\n| [pydantic](https://github.com/pydantic/pydantic) | Python | 365 | 9,648 | 0.3s |\n| [guava](https://github.com/google/guava) | Java | 891 | 8,377 | 2.4s |\n| [immich](https://github.com/immich-app/immich) | TypeScript | 919 | 7,957 | 0.6s |\n| [fastapi](https://github.com/tiangolo/fastapi) | Python | 881 | 5,713 | 0.5s |\n| [ant-design](https://github.com/ant-design/ant-design) | TypeScript | 2,947 | 5,452 | 0.9s |\n| [dify](https://github.com/langgenius/dify) | TypeScript | 4,903 | 5,038 | 1.9s |\n| [crawlee-python](https://github.com/apify/crawlee-python) | Python | 386 | 2,473 | 0.3s |\n| [flask](https://github.com/pallets/flask) | Python | 63 | 872 | <0.1s |\n| [cobra](https://github.com/spf13/cobra) | Go | 15 | 249 | <0.1s |\n| [gin](https://github.com/gin-gonic/gin) | Go | 41 | 574 | <0.1s |\n| Unity game (private) | C# | 129 | 1,018 | 0.1s |\n\n## Line Numbers for Targeted Reads\n\nEvery record includes `line_start` and `line_end` (1-indexed). Multi-line declarations span the full signature:\n\n```\n[METHOD] com.google.common.base.Converter.from\n  Signature: static Converter<A, B> from(Function<...> forward, Function<...> backward)\n  File: Converter.java:504-506          ← multi-line signature\n\n[METHOD] server.AlbumController.createAlbum\n  Signature: createAlbum(@Auth() auth: AuthDto, @Body() dto: CreateAlbumDto)\n  File: album.controller.ts:46          ← single-line\n```\n\nThis lets AI agents do **targeted reads** instead of reading full files:\n\n```python\n# Instead of reading the entire 600-line file:\nRead(\"Converter.java\")                     # 600 lines, ~12k tokens\n\n# Read just the method + context:\nRead(\"Converter.java\", offset=504, limit=10)  # 10 lines, ~200 tokens\n```\n\n## Benchmarks\n\nMeasured across 5 real-world projects in 5 languages, each using a 10-step cross-cutting research workflow.\n\n![Total Tokens, Cross-Language Comparison](https://raw.githubusercontent.com/Codeturion/codesurface/master/docs/images/01-total-tokens.png)\n\n| Language | Project | Files | Records | MCP | Skilled | Naive | MCP vs Skilled |\n|----------|---------|------:|--------:|----:|--------:|------:|---------------:|\n| C# | Unity game | 129 | 1,034 | **1,021** | 4,453 | 11,825 | 77% fewer |\n| TypeScript | immich | 694 | 8,344 | **1,451** | 4,500 | 14,550 | 68% fewer |\n| Java | guava | 891 | 8,377 | **1,851** | 4,200 | 26,700 | 56% fewer |\n| Go | gin | 38 | 534 | **1,791** | 2,770 | 15,300 | 35% fewer |\n| Python | codesurface | 9 | 40 | **753** | 2,000 | 10,400 | 62% fewer |\n\n![Hallucination Risk](https://raw.githubusercontent.com/Codeturion/codesurface/master/docs/images/04-hallucination.png)\n\nEven with follow-up reads for implementation detail, the hybrid MCP + targeted Read approach uses **44% fewer tokens** than a skilled Grep+Read agent and **87% fewer** than a naive agent:\n\n![Hybrid Workflow](https://raw.githubusercontent.com/Codeturion/codesurface/master/docs/images/03-hybrid.png)\n\n### Per-question breakdown\n\n![Per Question](https://raw.githubusercontent.com/Codeturion/codesurface/master/docs/images/02-per-step.png)\n\nSee [workflow-benchmark.md](workflow-benchmark.md) for the full step-by-step analysis across all languages.\n\n## Filtering What Gets Indexed\n\nBy default, codesurface skips common vendored, build, and VCS directories: `node_modules`, `vendor`, `bin`, `obj`, `dist`, `build`, `target`, `.git`, `.venv`, `__pycache__`, and a few dozen others. Git worktrees and submodules are also skipped.\n\nTo exclude additional paths:\n\n**Project-level (committed):** create a `.codesurfaceignore` file at your project root with one glob per line.\n\n```\ngenerated/**\ndocs/**\n**/*.pb.go\n```\n\n**Per-instance (CLI):** pass `--exclude` with comma-separated globs.\n\n```json\n{\n  \"command\": \"uvx\",\n  \"args\": [\"codesurface\", \"--project\", \"src\", \"--exclude\", \"generated/**,vendor/**\"]\n}\n```\n\nOther indexing flags:\n\n- `--include-submodules`: index git submodules (skipped by default)\n- `--language <name>`: pin to a single parser (e.g. `--language cpp`) instead of auto-detecting\n\n## Multiple Projects\n\nEach `--project` flag indexes one directory. To index multiple codebases, run separate instances with different server names:\n\n```json\n{\n  \"mcpServers\": {\n    \"codesurface-backend\": {\n      \"command\": \"uvx\",\n      \"args\": [\"codesurface\", \"--project\", \"/path/to/backend/src\"]\n    },\n    \"codesurface-frontend\": {\n      \"command\": \"uvx\",\n      \"args\": [\"codesurface\", \"--project\", \"/path/to/frontend/src\"]\n    }\n  }\n}\n```\n\nEach instance gets its own in-memory index and tools. The AI agent sees both and can query across projects.\n\n## Setup Details\n\n<details>\n<summary>Alternative installation methods</summary>\n\n**Using pip install:**\n```bash\npip install codesurface\n```\n```json\n{\n  \"mcpServers\": {\n    \"codesurface\": {\n      \"command\": \"codesurface\",\n      \"args\": [\"--project\", \"/path/to/your/src\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary>Project structure</summary>\n\n```\ncodesurface/\n├── src/codesurface/\n│   ├── server.py           # MCP server with 5 tools\n│   ├── db.py               # SQLite + FTS5 database layer\n│   ├── filters.py          # PathFilter (default exclusions, .codesurfaceignore, --exclude)\n│   └── parsers/\n│       ├── base.py         # BaseParser ABC\n│       ├── cpp.py          # C++ header parser\n│       ├── csharp.py       # C# parser\n│       ├── go.py           # Go parser\n│       ├── java.py         # Java parser\n│       ├── python_parser.py # Python parser\n│       └── typescript.py   # TypeScript/JavaScript parser\n├── pyproject.toml\n└── README.md\n```\n\n</details>\n\n<details>\n<summary>Troubleshooting</summary>\n\n**\"No codebase indexed\"**\n- Ensure `--project` points to a directory containing supported source files (`.cs`, `.h`, `.hpp`, `.go`, `.java`, `.py`, `.ts`, `.tsx`, `.js`, `.jsx`)\n- The server indexes at startup. Check stderr for `[codesurface] scanning N files...` and `[codesurface] done:` lines\n\n**Server won't start**\n- Check Python version: `python --version` (needs 3.10+)\n- Check `mcp[cli]` is installed: `pip install mcp[cli]`\n\n**Stale results after editing source files**\n- The index auto-refreshes on query misses. If you add a new class and query it, the server reindexes and retries automatically\n- You can also call `reindex()` manually to force an incremental update\n\n</details>\n\n---\n\n## Contact\n\nfuatcankoseoglu@gmail.com\n\n## License\n\n[MIT](LICENSE)\n",
  "bytes": 11098,
  "sha": "c75fe68d6736af7b4a62835b149e0bd2d8e2e02a96b3e4196fc864e279ce12da",
  "repo_slug": "codeturion/codesurface",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_codeturion_codesurface_26ec6f17/readme"
}