Skip to main content

mcp-minimal

A single local Python MCP server for a workspace of integrations (third-party services the AI can use: docs, dependencies, secret names) and tasks (units of work with goals, steps and progress). Both are typed folders in a virtual file tree, backed by a secret-name registry and on-the-fly Python script execution with the local .env injected. Secret VALUES never leave this machine and never enter the database.

Self-hosting? See SELF_HOSTING.md: one docker compose up, plus how to pull future updates.

Setup

cd apps/mcp-minimal
cp .env.example .env   # fill in your secret values

Get a token first by running uvx gcontext-mcp login (browser sign-in at https://app.gcontext.ai mints it).

Add to Claude Code

Published connector (hosted cloud):

claude mcp add-json gcontext '{
  "type": "stdio",
  "command": "uvx",
  "args": ["gcontext-mcp"],
  "env": { "GCONTEXT_TOKEN": "<your token>" }
}'

Pure-local (no cloud, own SQLite):

claude mcp add mcp-minimal -- uv run --directory /ABS/PATH/TO/apps/mcp-minimal python server.py

Add to Claude Desktop

The CLI commands above only work in Claude Code. For the Desktop app, edit the config file directly (Settings → Developer → Edit Config, or open it from):

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Add your server under mcpServers, then fully quit and reopen Claude Desktop.

Published connector (hosted cloud):

{
  "mcpServers": {
    "gcontext": {
      "command": "uvx",
      "args": ["gcontext-mcp"],
      "env": { "GCONTEXT_TOKEN": "<your token>" }
    }
  }
}

Pure-local (no cloud, own SQLite):

{
  "mcpServers": {
    "mcp-minimal": {
      "command": "uv",
      "args": ["run", "--directory", "/ABS/PATH/TO/apps/mcp-minimal", "python", "server.py"]
    }
  }
}

Note: Desktop has no slash-command prompts (/use-integration, etc.) — you drive the same tools by plain chat. Both modes need uv/uvx on your PATH.

Tools

  • tool_list_dir(path="/"), tool_read_file(path), tool_write_file(path, content), tool_delete(path)tool_write_file auto-creates missing parent folders
  • tool_secrets(), tool_register_secret(name, description), tool_unregister_secret(name), tool_setup_secrets(form=True)
  • tool_run_script(code) - runs uv run --env-file .env python -c "<code>"

The secret registry

The registry holds secret NAMES + descriptions only — it is for setup and verification, not runtime. It does NOT gate tool_run_script, which injects the whole .env regardless of what's registered.

  1. tool_register_secret(name, description) - declare a required secret.
  2. tool_setup_secrets(form=False) - append blank NAME= lines to .env for any registered secret not yet present, so the user just fills in the values (form=True opens a browser form).
  3. tool_secrets() - shows present per name so you can confirm setup.

How it works

  1. Write a file describing a 3rd-party operation and which secret NAMES it needs; declare those names with tool_register_secret.
  2. To act, read the file, generate Python, and call tool_run_script.
  3. Secret values resolve from the local .env at run time - never stored in the DB.

Security / trust model

tool_run_script runs arbitrary Python locally with your real .env injected — there is no sandbox. It is exactly as trusted as whatever drives the server. Run it on your own machine only; never expose this server remotely.

Script contract

  • Read secrets via os.environ["VAR"] - never hardcode, never load_dotenv.
  • Use only registered names that show present_locally: true.
  • Exit codes: 0 OK, 2 missing secret (KeyError), 1 any other failure.

Config (env vars)

  • MCP_MINIMAL_DB - SQLite path (default db.sqlite next to server.py).
  • MCP_MINIMAL_ENV_FILE - secret-values file (default .env next to server.py).

Testing

Every test file is a standalone self-check: run it alone and it either prints ok or an assert blows up with the offending value. One OS process per file (several mutate os.environ at import), no shared fixtures, no framework, except test_billing.py, which is pytest because it needs monkeypatch.

Run everything: make test. The journey test needs the local docker Postgres (make pg); it skips itself with a message when Postgres is down.

Three rings, inside out:

  1. Pure logic, no I/O at all.
  2. One component, boundary faked, the unit under test is real, the thing it talks to (cloud RPC, DB, keychain) is stubbed in-file.
  3. Full stack, the real connector talking HTTP to the real backend on a throwaway database.
File What it verifies Ring / boundary
test_digest.py digest.py: frontmatter parsing, folder type detection, staleness tiers, compute_digest end to end 1, pure
test_run_script.py server.py script helpers: secret scrubbing (_scrub), PEP 723 inline deps (_inline_deps) 1, pure
test_read_tools.py server.py read path: partial reads (_read_view), _glob_paths, read_many batching + 200KB cap, grep truncation flag 2, cloud _rpc stubbed
test_commands.py server.py dynamic /_commands/*.md MCP prompts: frontmatter split, listing, {{input}} substitution, cloud-down fallback 2, cloud stubbed
test_secrets_form.py server.py secret store: keychain writes, .env fallback + legacy migration, blank-unsets 2, in-memory keyring
test_token_login.py cloud_api.py self-host token login (container shape: no .env, no OAuth creds) 2, env cleared
test_grep.py cloud_api.py search: substring/regex/context/glob/pagination, _tree_entries folder typing 2, DB stubbed
test_context_index.py cloud_api.py connect-payload index builder (_index_lines) 2, DB stubbed
test_dashboard_rpc.py cloud_api.py dashboard batch-read path: read_many, overview.mtimes 2, DB stubbed
test_billing.py cloud_api.py billing_info: free vs pro, payment link config (pytest) 2, fake DB conn
test_journey.py The whole create-integration flow an AI agent drives: write module files, register secret, scaffold .env, set value, presence, run_script probe with auto deps + scrubbing, typed-folder visibility, delete 3, real server.py to HTTP /rpc to cloud_api.py to throwaway Postgres

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gcontext_mcp-0.3.1.tar.gz (21.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gcontext_mcp-0.3.1-py3-none-any.whl (22.7 kB view details)

Uploaded Python 3

File details

Details for the file gcontext_mcp-0.3.1.tar.gz.

File metadata

  • Download URL: gcontext_mcp-0.3.1.tar.gz
  • Upload date:
  • Size: 21.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.16

File hashes

Hashes for gcontext_mcp-0.3.1.tar.gz
Algorithm Hash digest
SHA256 2178d9bdaed81c3b9d047cba93d70c49db69daaf0b902477b0b7b20b363658d9
MD5 3da7ce0d160f8713a1ca345981065999
BLAKE2b-256 43db0e2aeed471e98a361e0a22055e503d23e0127811b3af47499458ecb7a2e3

See more details on using hashes here.

File details

Details for the file gcontext_mcp-0.3.1-py3-none-any.whl.

File metadata

File hashes

Hashes for gcontext_mcp-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0a1b25cda87ca00694f0520e217f88c20f10dbc2e8708e31ccb1ab5b1f1a221a
MD5 8dbe57101be6103e9133002b49a4bba3
BLAKE2b-256 677660d8036f1ae757ddd6e8d0e1d467da2f13d56c886f10efbfd2768176de74

See more details on using hashes here.

Release history Release notifications | RSS feed

0.3.3

2 files

This release

0.3.1 This release

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page