ollamadev-mcp-server
ollamadev-mcp-server
Companion MCP server for the OllamaDev Android app, written with the MCP Python SDK v2 beta.
It exposes a comprehensive toolbox of 46 tools that OllamaDev agents can invoke via MCP_CALL: directives during every SDLC sprint phase. It also includes an agentic self-prompt tool (suggest_next_action) that asks a local Ollama model which tool to call next.
Server layout
ollamadev-mcp-server/
├── pyproject.toml
├── README.md
├── server.py # thin bootstrap
└── ollamadev_mcp_server/
├── constants.py
└── tools/
├── filesystem.py # list/read/write/delete/move files
├── code.py # search, outline, find symbol, todos
├── build.py # gradle tests, lint, build, test parsing
├── sprint.py # phase artifacts, backlog tasks, outcome eval
├── memory.py # agent key/value memory
├── meta.py # describe_tools, suggest_next_action, ping
├── patch.py # apply_file_patch
├── git_tools.py # git status/diff/commit/log
├── dependencies.py # add_gradle_dependency
├── observability.py # get_task_transcript
└── settings.py # get/update/reset server settingsRequirements
Python ≥ 3.11
uv(recommended) or pipOptional: a local Ollama instance for the
suggest_next_actiontool (OLLAMA_URL)
Run
# with uv
uv sync
uv run serve
# with pip in a venv
python3 -m venv .venv
.venv/bin/pip install -r pyproject.toml
.venv/bin/python3 server.pyServer starts on http://0.0.0.0:5000/mcp.
Override workspace path: WORKSPACE_ROOT=/path/to/OllamaDev uv run serve
Override Ollama URL: OLLAMA_URL=http://localhost:11434 uv run serve
Connect from OllamaDev
Open OllamaDev → MCP Servers tab → Add Server
Name:
OllamaDev ToolsType:
FilesystemURL:
http://<your-machine-ip>:5000/mcpTap Connect — status turns Connected, toolsCount = 36
Tool catalog
Filesystem
Tool | Description | Phase |
| List relative file paths under the workspace | DISCOVERY |
| Read a file by relative path | all |
| Write/overwrite a file | IMPLEMENTATION |
| Destructive: delete a file | IMPLEMENTATION |
| Move/rename a file | IMPLEMENTATION |
Code intelligence
Tool | Description | Phase |
| Grep across source files | DISCOVERY / VERIFICATION |
| Extract Kotlin signatures with line numbers | DESIGN |
| Find a class/function/property declaration | DESIGN / INTEGRATION |
| Extract | INTEGRATION / RETROSPECTIVE |
Surgical edits & dependencies
Tool | Description | Phase |
| Apply a unified diff patch to an existing file | IMPLEMENTATION |
| Add a dependency to | IMPLEMENTATION |
Build & verification
Tool | Description | Phase |
| Run unit tests and return output | VERIFICATION |
| Compile-only build ( | VERIFICATION |
| Parse raw Gradle output into structured JSON | VERIFICATION |
| Run Android Lint | VERIFICATION |
| Run ktlint/detekt if installed | VERIFICATION |
| Run ktlint (default: | VERIFICATION |
| Run detekt (tries | VERIFICATION |
| Parse JUnit XML reports into structured JSON (totals + failure details) | VERIFICATION |
| Parse a JaCoCo XML report into LINE/BRANCH/INSTRUCTION coverage | VERIFICATION / INTEGRATION |
| Run | VERIFICATION |
| Roborazzi record/verify screenshot tests on the JVM (no emulator) | VERIFICATION |
| Read | INTEGRATION |
Execution sandbox
Tool | Description | Phase |
| Run pytest in the workspace and return structured pass/fail | VERIFICATION |
| Run | VERIFICATION |
| Destructive: run arbitrary shell command in workspace root | VERIFICATION |
| Report pytest/gradlew availability and workspace root | VERIFICATION / META |
Sprint workflow
Tool | Description | Phase |
| Append a task to | RETROSPECTIVE |
| List | RETROSPECTIVE |
| Read a specific phase artifact | RETROSPECTIVE |
| Overwrite a phase artifact | RETROSPECTIVE |
| Compare artifact to goal, return structured critique | RETROSPECTIVE |
Memory
Tool | Description | Phase |
| Persist a fact to | RETROSPECTIVE |
| Retrieve a stored fact | RETROSPECTIVE |
| List all memory keys | RETROSPECTIVE |
| Delete one memory entry | RETROSPECTIVE |
Git
Tool | Description | Phase |
| Show | INTEGRATION / RETROSPECTIVE |
| Stage all changes and commit | RETROSPECTIVE / INTEGRATION |
| Recent commit log | RETROSPECTIVE / INTEGRATION |
Observability
Tool | Description | Phase |
| Read an exported task transcript | OBSERVABILITY |
Meta / agentic
Tool | Description |
| Server version and uptime |
| Return a markdown catalog of tools |
| Ask Ollama which tool to call next |
Cloudflare Computer (remote virtual workspace)
OllamaDev agents can also operate a Cloudflare Computer
workspace — a persistent, SQLite-backed virtual filesystem running in a
Durable Object with pluggable execution backends — through the HTTP surface
that the computer repo's example Workers expose
(PUT/GET /c/<name>/file/workspace/<path>, POST /c/<name>/exec). These
tools are a thin HTTP client; if no Cloudflare Computer instance is reachable
they return a helpful, structured error.
Production hardening built into the module:
Config validation — base URL must be
http(s), workspace name must match[A-Za-z0-9_-]{1,64}, timeouts are bounded (1–300s). Bad env is a clearCONFIG_ERROR, not a crash.Resilient transport — connection-pooled
requests.Session, exponential backoff on transient network errors, bounded retries on502/503/504, and a circuit breaker (cloudflare-computer) that trips on a dead endpoint so a broken backend can't be hammered from every agent turn.Input safety — paths are normalized and reject
.., control characters, and over-long/deep input;gitargs are restricted to known subcommands and refuse shell metacharacters (;,&&,|,`,$(, ...).Output caps — file reads capped at 2 MiB (
max_read_bytes) and exec stdout/stderr at 256 KiB (max_exec_output_bytes), each with atruncatedflag; binary files round-trip via base64 (binary=True/content_b64=).Audit + approval —
cf_write_workspace_file,cf_exec_workspace, and mutatingcf_git_workspacecalls are written tostore/audit.log;cf_exec_workspace/cf_git_workspacearedestructiveHint=trueso OllamaDev's MCP risk gate requires human approval first.
Configure with env (or persisted settings: cf_computer_base_url,
cf_computer_workspace, cf_computer_timeout):
export CF_COMPUTER_BASE_URL=http://127.0.0.1:8787 # Worker hosting the DO
export CF_COMPUTER_WORKSPACE=compute # DO name / workspace id
uv run serveTool | Description | Safety |
| Connectivity + config + circuit-breaker health | read-only |
| List a directory via the exec surface | read-only (via exec) |
| Read a file (base64 for binary) with size cap | read-only |
| Write/overwrite a file | additive + audited |
| Run a shell command / quoted argv | destructiveHint + audited |
| Run | destructiveHint if mutating + audited |
Server settings
Tool | Description | Phase |
| Read-only JSON snapshot of effective config (secrets masked) | META |
| Persist config overrides to | META |
| Destructive: delete the persisted settings file | META |
Server settings
Settings are persisted as JSON (default: <WORKSPACE_ROOT>/store/server_settings.json,
overridable with the OLLAMADEV_SETTINGS_FILE env var) and follow the precedence:
environment variable > persisted settings file > code defaultAllowed keys: workspace_root, ollama_url, ollama_api_key,
anthropic_api_key, anthropic_auth_token, anthropic_base_url,
default_cloud_model, cf_computer_base_url, cf_computer_workspace,
cf_computer_timeout. Secret values are never echoed back in full — get_server_settings
reports them masked (***) with *_set flags.
# Read the effective configuration (env > persisted > default).
curl -s -X POST http://localhost:5000/mcp \
-H 'Content-Type: application/json' -H 'MCP-Protocol-Version: 2025-06-18' \
-H 'Mcp-Session-Id: <session-id>' \
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"get_server_settings","arguments":{}}}'
# Persist an override (takes effect on next server restart).
curl -s -X POST http://localhost:5000/mcp \
-H 'Content-Type: application/json' -H 'MCP-Protocol-Version: 2025-06-18' \
-H 'Mcp-Session-Id: <session-id>' \
-d '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"update_server_settings","arguments":{"settings":{"ollama_url":"http://10.0.2.2:11434"}}}}'Constants are resolved once at server startup, so update_server_settings reports which
keys require a restart; the file itself is written atomically (temp file + rename).
Agentic self-prompt (suggest_next_action)
If you run a local Ollama instance, agents can ask it to choose the next tool:
MCP_CALL: suggest_next_action | {
"goal": "Add a Room migration for sprint tables",
"phase": "IMPLEMENTATION",
"context": "SprintCycle and SprintArtifact entities already exist in Entities.kt",
"model": "llama3"
}Response shape:
{
"tool_name": "search_workspace",
"arguments": {"pattern": "@Database", "file_glob": "*.kt"},
"reasoning": "Need to find the AppDatabase declaration before adding the migration.",
"confidence": 0.92
}If Ollama is not reachable, the tool returns a graceful JSON failure with tool_name: null and confidence: 0.
Per-phase example directives
DISCOVERY
MCP_CALL: list_workspace_files | {"root": "app/src/main/java/com/example/data"}
MCP_CALL: search_workspace | {"pattern": "class.*Dao", "context_lines": 0}DESIGN
MCP_CALL: get_file_outline | {"path": "app/src/main/java/com/example/data/Entities.kt"}
MCP_CALL: find_symbol | {"name": "AppDatabase", "symbol_type": "class"}IMPLEMENTATION
MCP_CALL: apply_file_patch | {"path": "app/src/main/java/com/example/data/Foo.kt", "patch": "--- a/...\n+++ b/...\n@@ ...\n"}
MCP_CALL: add_gradle_dependency | {"alias": "retrofit", "group": "com.squareup.retrofit2", "name": "retrofit", "version": "2.11.0"}
MCP_CALL: write_workspace_file | {"path": "app/src/main/java/com/example/data/NewRepo.kt", "content": "package..."}
MCP_CALL: move_workspace_file | {"src": "Old.kt", "dst": "New.kt"}VERIFICATION
MCP_CALL: run_gradle_build | {"module": "app", "variant": "Debug"}
MCP_CALL: run_gradle_tests | {"module": "app", "test_filter": "com.example.SprintOrchestratorTest"}
MCP_CALL: parse_test_results | {"gradle_output": "..."}
MCP_CALL: run_lint | {"module": "app"}
MCP_CALL: search_workspace | {"pattern": "TODO|FIXME"}INTEGRATION
MCP_CALL: git_status_diff | {}
MCP_CALL: get_build_config | {}
MCP_CALL: get_todos | {}
MCP_CALL: find_symbol | {"name": "SprintPhase", "symbol_type": "class"}RETROSPECTIVE
MCP_CALL: evaluate_sprint_outcome | {"cycle_id": 1, "phase": "verification"}
MCP_CALL: git_commit_checkpoint | {"message": "Sprint 1 checkpoint"}
MCP_CALL: create_sprint_task | {"title": "Wire SprintOrchestrator into UI", "description": "...", "tier": "4", "priority": "high"}
MCP_CALL: update_phase_artifact | {"cycle_id": 1, "phase": "retrospective", "content": "..."}
MCP_CALL: store_memory | {"key": "lesson-learned", "value": "..."}Risk gating
delete_workspace_file and run_shell_command are annotated with destructiveHint=true so OllamaDev's isRiskyMcpCallReason() gate triggers a user approval before destructive calls execute. The gate now records an MCP_CALL_GATED TaskStep before showing the approval dialog and surfaces the matched reason (annotation-based destructiveHint=true or the matched keyword) in PendingApproval.detail, rendered in the dialog as Reason: ${approval.detail}. git_commit_checkpoint also contains "commit" which may be flagged as a keyword match depending on the app's keyword list; the tool is additive and safe. All other tools are read-only or additive.
Verify manually
# 1. Handshake
curl -s -X POST http://localhost:5000/mcp \
-H 'Content-Type: application/json' \
-H 'MCP-Protocol-Version: 2025-06-18' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
# 2. List all 36 tools
curl -s -X POST http://localhost:5000/mcp \
-H 'Content-Type: application/json' \
-H 'MCP-Protocol-Version: 2025-06-18' \
-H 'Mcp-Session-Id: <session-id>' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
# 3. Call a tool
curl -s -X POST http://localhost:5000/mcp \
-H 'Content-Type: application/json' \
-H 'MCP-Protocol-Version: 2025-06-18' \
-H 'Mcp-Session-Id: <session-id>' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"ping","arguments":{}}}'MCP Python SDK v2 — key changes from v1
v1 | v2 |
|
|
|
|
Transport in constructor |
|
|
|
Sync tools block event loop | Sync tools run on worker threads automatically |
Server callbacks for missing args |
|
Manual JSON Schema | Type hints auto-converted to JSON Schema |
Add | Pin exact: |
Full article: https://pydantic.dev/articles/mcp-python-sdk-v2-beta
Migration guide: https://py.sdk.modelcontextprotocol.io/v2/migration/