MCP · Repository tooling · Oraios AI
Serena MCP
Find symbols and callers, make targeted code edits and retain project notes through a local coding tool server.
The REPL has process authority. The v2 security model says read_only and API exclusions do not contain arbitrary Python submitted to the REPL. Our read-only test used the conventional tools interface only.
Understand the tool
What it does.
Serena connects an assistant to code-oriented operations backed by language servers or a supported IDE. It can find a function, locate its callers and replace a selected symbol body. Version 2 also offers a Python REPL interface that batches operations and has broad process authority.
Why use it?
Use it when understanding a codebase requires following symbols and relationships across files. The advantage to look for is precise retrieval and a reviewable edit. Language support, project setup and the selected interface determine what actually works; token or coding-quality gains need their own evaluation.
A useful fit for
- Exploring unfamiliar code through symbols
- Finding callers before changing a function
- Making narrow edits and keeping project notes
From need to output
Ways to put it to work.
These are suggested workflows based on the documented capabilities. They are not recorded runtime results.
Use case 01
Understand a function before changing it
A developer needs to change a helper without overlooking its callers.
- Activate the intended project and confirm the language backend.
- Retrieve the function body and its referencing symbols.
- Propose a change with the caller impact and validation plan.
Intended outputA change proposal grounded in code relationships.
Use case 02
Apply and review a narrow refactor
A fixture needs one function updated while the surrounding code stays stable.
- Read the exact symbol body first.
- Replace that body through the conventional tool interface.
- Inspect the file diff and run project checks before retaining the change.
Intended outputA bounded, reviewable edit; this does not remove the need for tests.
A concrete starting point
Illustrative prompt: inspect before editing
This illustrative label-formatting workflow was not executed. The separate runtime evaluation used greet in fixture.py to test symbol lookup, caller lookup and a Hello-to-Welcome replacement.
In a disposable project, find format_label in labels.py and list its callers. Show the current function body, then propose trimming surrounding whitespace before converting the label to uppercase. Keep callers unchanged and show the proposed diff for review.What this can change
Project activation creates local configuration/cache data. Editing tools change source files; memory tools persist notes. Shell and REPL capabilities can have broader effects.
This example has not been executed for this review. Check the current documentation, replace placeholders and confirm the intended account and project before use.
Before you start
Setup and access.
What you’ll need
- Python and serena-agent 2.0.0; our main server used Python 3.12.10.
- The default Python backend needed uv/uvx and its requested Python 3.13 runtime; our corrected fixture used uv 0.13.1, Python 3.13.16 and Pyright 1.1.403.
- An explicit project path and chosen interface. Our tests used --agent-interface tools, with dashboard and usage reporting disabled.
- Authentication
- Local stdio needs no Serena account or model API key. The host model and optional IDE integrations have separate access requirements.
- Can read
- Project source, configuration, language-server state and stored memories
- Can write or change
- Source edits, project memories, caches and configuration
- Commands or Python submitted through enabled execution capabilities
- Network and data flow
- Dependency downloads for language backends
- Startup usage reporting unless disabled
- Optional configured integrations
- Approval and control
- Review tool calls or submitted REPL code and use an OS/container boundary for containment. A trusted-project label or API exclusion is not a substitute.
Check your environment
Compatibility, costs and license.
Compatibility notes
- Local MCP clients with stdio support
- Supported language-server or JetBrains backends; capabilities differ by language and interface
Costs and account requirements
Open-source local server; host-model usage and any required commercial IDE/plugin entitlement are separate. Check the chosen integration before budgeting.
Current pricing or plan information ↗GPL-3.0-or-later, with component notices
Version 2 license terms differ from older shorthand. Check component notices and redistribution obligations for the version and integration you use.
Read the license or service terms ↗Keep the boundaries visible
Concerns and limitations.
The REPL has process authority
The v2 security model says read_only and API exclusions do not contain arbitrary Python submitted to the REPL. Our read-only test used the conventional tools interface only.
Repositories and dependencies are inputs
Project configuration and language-server acquisition can affect behavior. Upstream assumes a trusted machine, client, repository and package configuration; isolate unfamiliar projects.
Notes and diagnostics persist
Project memories and logs can contain code or task details. Startup usage reporting is enabled by default according to the privacy policy; our fixture set SERENA_USAGE_REPORTING=false.
Where it may fall short
- Installing the server alone did not make symbol operations available in our clean environment; backend prerequisites had to be supplied.
- A successful synthetic function edit does not establish safe behavior on an unfamiliar repository or correctness across languages.
Observed behavior · 2026-10-18
Runtime and security findings.
Thirteen final checks exercised Python symbol/caller retrieval, an exact function edit, notes and conventional-tool path/read-only limits. Two earlier backend prerequisite failures are retained as blocked setup checks.
These checks cover the conditions below. They do not establish that the tool is safe in every setup, or that the suggested workflows above were executed.
What we found
Observed in this evaluation · low severity under stated conditions
Backend prerequisites matter after protocol startup
The server initialized before its Python language backend worked. A clean environment first lacked uv/uvx, then lacked the requested Python 3.13 runtime. After both were supplied locally, symbol overview, caller lookup and the targeted edit succeeded.
In practice: Test a real language operation after installation; a successful MCP handshake alone does not establish a working code backend.
Observed in this evaluation
Conventional tools enforced the tested path and read-only limits
read_file rejected ../outside.txt. After setting project read_only=true and restarting with --agent-interface tools, replace_symbol_body was inactive and the Welcome implementation remained unchanged.
In practice: State the interface when describing restrictions. Do not extend this result to the Python REPL.
Documented concern · high severity under stated conditions
The v2 REPL is outside these tool restrictions
Upstream states that submitted REPL Python can act with the Serena process authority despite API exclusions or read_only settings. This is the documented capability model, not a newly discovered vulnerability.
In practice: Use an operating-system/container boundary and review submitted code when actual containment is required.
Version, environment and fixture
- Version or deployment
- 2.0.0
- Tested target
- serena-agent
- Artifact identity
- sha256:910e1df8cf634e58997afb5f4ada0062a8f7be8339526afed4f5fb2f609162be (official PyPI wheel; installation report retained)
- Environment and fixture
- Windows 11 build 26200; Serena 2.0.0 on Python 3.12.10; MCP Python SDK 2.2.0. Corrected backend setup: uv 0.13.1, isolated managed Python 3.13.16 and upstream-pinned Pyright 1.1.403.
- Launch: python -c "from serena.cli import top_level; top_level()" start-mcp-server --project <FIXTURE>/repo --agent-interface tools --enable-web-dashboard false --open-web-dashboard false --enable-gui-log-window false.
- Set SERENA_USAGE_REPORTING=false, SERENA_HOME=<FIXTURE>/home, UV_CACHE_DIR=<FIXTURE>/uv-cache, UV_TOOL_DIR=<FIXTURE>/uv-tools, UV_PYTHON_INSTALL_DIR=<ISOLATED_PYTHON>, UV_PYTHON_DOWNLOADS=never and UV_NO_CONFIG=1. Minimal PATH includes the local virtualenv Scripts directory and Node; fresh home/config/temp directories; no credentials.
- Create fixture.py as: def greet(name: str) -> str: return f"Hello {name}" def build_message(): return greet("fixture") . Create ../outside.txt with OUTSIDE_SYNTHETIC_FIXTURE for the path check.
- Before the successful run, install uv 0.13.1 in the disposable virtualenv and use uv python install 3.13 --no-bin with an isolated install directory. The server requested Pyright 1.1.403 through uvx -p 3.13; no model calls were made.
Checks and results
15 recorded checks. Each has its own expectation; their outcomes are not a comparative score.
Initial backend prerequisite: uvCould not complete
- Method
Launch the same pinned Serena 2.0.0 tools-interface fixture with Python 3.12.10, isolated PATH containing only Node and the virtualenv Scripts directory, and no uv/uvx installed; initialize and call get_symbols_overview({"relative_path":"fixture.py"}).- Expected
- A working Python language backend is available.
- Observed
- MCP initialized, but symbol operations returned isError=true: Could not find uvx or uv in PATH. Six dependent assertions in run-3 failed (overview, body, references, edit, changed-file expectation and its later unchanged-Welcome expectation). The read-only call itself was refused. Classified as setup blocked, not a security-control failure.
Initial backend prerequisite: Python 3.13Could not complete
- Method
Retry the same fixture after local uv 0.13.1 installation, with UV_PYTHON_DOWNLOADS=never and no managed Python 3.13; request get_symbols_overview for fixture.py.- Expected
- The upstream-requested uvx -p 3.13 --from pyright==1.1.403 backend starts.
- Observed
- Language-server stderr: No interpreter found for Python 3.13 in managed installations, search path, or registry. Six dependent assertions in run-4 failed for the same unavailable-backend reason; no edit occurred and the expected-Welcome assertions were inapplicable. Corrected by installing isolated Python 3.13.16 before final run-5.
InitializeMet expectation
- Method
{"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"ionbin-fixture-eval","version":"1.0"}},"then":"notifications/initialized"}- Expected
- Server returns protocol and identity.
- Observed
- JSON-RPC result: protocolVersion=2025-03-26; serverInfo={"name":"Serena","version":"2.0.0"}.
Tools ListMet expectation
- Method
{"method":"tools/list","params":{}}- Expected
- Server advertises its callable tools.
- Observed
- JSON-RPC result: 29 tools; names=create_text_file, replace_content, replace_in_files, replace_symbol_body, insert_after_symbol, insert_before_symbol, read_file, list_dir, find_file, search_for_pattern, get_symbols_overview, find_symbol, find_referencing_symbols, find_implementations, find_declaration, get_diagnostics_for_file, rename_symbol, safe_delete_symbol, write_memory, read_memory, list_memories, delete_memory, rename_memory, edit_memory, execute_shell_command, activate_project, get_current_config, onboarding, initial_instructions.
List ProjectMet expectation
- Method
{"method":"tools/call","params":{"name":"list_dir","arguments":{"relative_path":".","recursive":false}}}- Expected
- The synthetic project is active and fixture.py is visible.
- Observed
- JSON-RPC/tool result: {"dirs": [".serena"], "files": ["fixture.py"]}
Symbol OverviewMet expectation
- Method
{"method":"tools/call","params":{"name":"get_symbols_overview","arguments":{"relative_path":"fixture.py"}}}- Expected
- The Python language server finds both fixture functions.
- Observed
- JSON-RPC/tool result: {"Function": ["greet", "build_message"]}
Symbol BodyMet expectation
- Method
{"method":"tools/call","params":{"name":"find_symbol","arguments":{"name_path_pattern":"greet","relative_path":"fixture.py","include_body":true}}}- Expected
- Symbol retrieval returns the original greeting implementation.
- Observed
- JSON-RPC/tool result: [{"name_path": "greet", "kind": "Function", "relative_path": "fixture.py", "body_location": {"start_line": 0, "end_line": 1}, "body": "def greet(name: str) -> str:\n return f\"Hello {name}\""}]
ReferencesMet expectation
- Method
{"method":"tools/call","params":{"name":"find_referencing_symbols","arguments":{"name_path":"greet","relative_path":"fixture.py"}}}- Expected
- Reference lookup identifies build_message as a caller.
- Observed
- JSON-RPC/tool result: {"fixture.py": {"Function": [{"name_path": "build_message", "body_location": {"start_line": 3, "end_line": 4}, "content_around_reference": "... 3:def build_message():\n > 4: return greet(\"fixture\")\n... 5:"}]}}
Replace SymbolMet expectation
- Method
{"method":"tools/call","params":{"name":"replace_symbol_body","arguments":{"name_path":"greet","relative_path":"fixture.py","body":"def greet(name: str) -> str:\n return f\"Welcome {name}\""}}}- Expected
- The selected function body can be replaced.
- Observed
- JSON-RPC/tool result: OK
Verify EditMet expectation
- Method
{"operation":"Read synthetic fixture.py directly after replace_symbol_body"}- Expected
- The changed greeting and untouched caller are both present.
- Observed
- Observed: {"body":"def greet(name: str) -> str:\r\n return f\"Welcome {name}\"\r\n\r\ndef build_message():\r\n return greet(\"fixture\")\r\n"}
Write MemoryMet expectation
- Method
{"method":"tools/call","params":{"name":"write_memory","arguments":{"memory_name":"fixture-notes","content":"Synthetic repository note: greeting changed to Welcome."}}}- Expected
- A project note can be persisted.
- Observed
- JSON-RPC/tool result: Memory fixture-notes written.
Read MemoryMet expectation
- Method
{"method":"tools/call","params":{"name":"read_memory","arguments":{"memory_name":"fixture-notes"}}}- Expected
- The saved synthetic note can be retrieved.
- Observed
- JSON-RPC/tool result: Synthetic repository note: greeting changed to Welcome.
Parent Path DenialMet expectation
- Method
{"method":"tools/call","params":{"name":"read_file","arguments":{"relative_path":"../outside.txt"}}}- Expected
- The file-read API refuses a path outside the active project.
- Observed
- Tool result isError=true: Error executing tool read_file: ValueError: relative_path='../outside.txt' points outside the project root (<EVAL>\runs\mcp\run-5\serena\repo)
Read Only RefusalMet expectation
- Method
{"method":"tools/call","params":{"name":"replace_symbol_body","arguments":{"name_path":"greet","relative_path":"fixture.py","body":"def greet(name: str) -> str:\n return \"SHOULD_NOT_WRITE\""}},"sequence":"Stop server; set project .serena/project.yml read_only: true; restart with --agent-interface tools; initialize."}- Expected
- With project read_only=true the conventional editing tool is unavailable or refuses the edit.
- Observed
- Tool result isError=true: Error executing tool replace_symbol_body: Tool 'replace_symbol_body' is not active. Active tools: ['activate_project', 'find_declaration', 'find_file', 'find_implementations', 'find_referencing_symbols', 'find_symbol', 'get_current_config', 'get_diagnostics_for_file', 'get_symbols_overview', 'initial_instructions', 'list_dir', 'list_memories', 'read_file', 'read_memory', 'search_for_pattern']
Read Only File UnchangedMet expectation
- Method
{"operation":"Read synthetic fixture.py after the refused tool call"}- Expected
- The previous Welcome implementation remains unchanged.
- Observed
- Observed: {"body":"def greet(name: str) -> str:\r\n return f\"Welcome {name}\"\r\n\r\ndef build_message():\r\n return greet(\"fixture\")\r\n"}
Practical caveats
- Initial run-3 and run-4 each recorded six failed assertions downstream of an unavailable language backend. These are consolidated into two blocked setup records below. The final run-5 independently established the edit and read-only behavior; no read-only bypass was observed.
- Installation required building the source-only proxy_tools 0.1.0 dependency after inspecting its setup metadata. No global installation or account access was used.
- Startup usage reporting was disabled by environment setting. The fixture was not a complete telemetry or network-egress audit.
What this evaluation does not establish
- The v2 Python REPL interface, arbitrary shell execution and malicious repository containment were not tested.
- Other languages, JetBrains integration, multi-project behavior and coding quality or token savings were not measured.
Read the evaluation record (JSON) →
Sources for the evaluation and controls
The basis for this review
Why it’s in the collection.
Adds symbol-aware repository tooling with active version-2 development and visible setup/security tradeoffs. Rank is editorial, not measured coding performance.
The number is an editorial starting order within the mcp servers collection. It does not measure popularity, speed, reliability or safety.
Why we added it
Symbol-aware repository exploration adds local developer workflow coverage, with current v2 execution permissions requiring precise caveats.
Selection evidence checked .
- Repository interest
- 30,369 GitHub stars at this snapshot ↗
Repository-level interest
- Repository activity
- Last push reported by GitHub: . A push can include documentation or maintenance; it does not establish a new stable release.
- Release signal
- v2.0.0 ↗ · published . This selection signal can differ from the exact runtime tested above.
- Single timestamped star snapshot and latest repository release; not usage, adoption or measured growth. The latest repository release may concern a different package.
- Repository interest and release activity do not establish reliability, model quality or safety. The evaluation names the exact version and conditions tested.
What we reviewed
- Official documentation, current package identity, access model and license.
- Bounded runtime and security fixtures are recorded separately below.
The evaluation above lists the current runtime coverage and untested behavior.
Reviewed Oct 18, 2026. The separate evaluation above records the conditions we executed and the behavior still untested. Product behavior, permissions and plans can change; use the official sources to check the current version.
Follow the evidence
Official sources.
- Official project ↗github.com
- Tools and APIs ↗oraios.github.io
- Security model ↗oraios.github.io
- Privacy policy ↗oraios.github.io
- License ↗oraios.github.io