Skip to main content
Glama

opensrc-mcp

A codemode MCP server for fetching and querying dependency source code.

Why?

Traditional MCP exposes tools directly to LLMs. This server uses the codemode pattern: agents write JavaScript that executes server-side, and only results return. Benefits:

  • Context efficient - Large source trees stay server-side

  • Batch operations - One call to search/read multiple files

  • LLMs are better at code - More training data for JS than tool-calling

Related MCP server: Satori

Installation

npm install -g opensrc-mcp
# or
npx opensrc-mcp

OpenCode Configuration

Add to your OpenCode config (~/.config/opencode/config.json or project opencode.json):

{
  "mcp": {
    "opensrc": {
      "type": "local",
      "command": "npx",
      "args": ["-y", "opensrc-mcp"]
    }
  }
}

Tool

execute

Single tool exposing all operations. Agents write JS that runs server-side; only results return.

// Available in sandbox:
declare const opensrc: {
  // Read operations
  list(): Source[];
  has(name: string, version?: string): boolean;
  get(name: string): Source | undefined;
  files(sourceName: string, glob?: string): Promise<FileEntry[]>;
  tree(sourceName: string, options?: { depth?: number }): Promise<TreeNode>;
  grep(pattern: string, options?: {
    sources?: string[];
    include?: string;
    maxResults?: number;
  }): Promise<GrepResult[]>;
  astGrep(sourceName: string, pattern: string, options?: {
    glob?: string;
    lang?: string | string[];
    limit?: number;
  }): Promise<AstGrepMatch[]>;
  read(sourceName: string, filePath: string): Promise<string>;
  readMany(sourceName: string, paths: string[]): Promise<Record<string, string>>;
  resolve(spec: string): Promise<ParsedSpec>;

  // Mutation operations
  fetch(specs: string | string[], options?: { modify?: boolean }): Promise<FetchedSource[]>;
  remove(names: string[]): Promise<RemoveResult>;
  clean(options?: {
    packages?: boolean;
    repos?: boolean;
    npm?: boolean;
    pypi?: boolean;
    crates?: boolean;
  }): Promise<RemoveResult>;
};

declare const sources: Source[];  // All fetched sources
declare const cwd: string;        // Project directory

Examples:

// List all fetched sources
async () => opensrc.list()

// Fetch npm package (auto-detects version from lockfile)
async () => opensrc.fetch("zod")

// Fetch multiple packages
async () => opensrc.fetch(["zod", "drizzle-orm", "hono"])

// Fetch GitHub repo at specific ref
async () => opensrc.fetch("vercel/ai@v3.0.0")

// Fetch from other registries
async () => opensrc.fetch("pypi:requests")
async () => opensrc.fetch("crates:serde")

// Get directory tree
async () => opensrc.tree("zod", { depth: 2 })

// Find TypeScript files
async () => opensrc.files("zod", "**/*.ts")

// Text search
async () => opensrc.grep("parse", { sources: ["zod"], include: "*.ts" })

// AST search (structural pattern matching)
async () => opensrc.astGrep("zod", "function $NAME($$$ARGS)", { glob: "**/*.ts" })

// Read a specific file
async () => opensrc.read("zod", "src/index.ts")

// Read multiple files (supports globs)
async () => opensrc.readMany("zod", ["src/index.ts", "packages/*/package.json"])

// Remove a source
async () => opensrc.remove(["zod"])

// Clean all npm packages
async () => opensrc.clean({ npm: true })

Package Formats

Format

Example

Description

<name>

zod

npm (auto-detects version)

<name>@<version>

zod@3.22.0

npm specific version

npm:<name>

npm:react

explicit npm

pypi:<name>

pypi:requests

Python/PyPI

pip:<name>

pip:flask

alias for pypi

crates:<name>

crates:serde

Rust/crates.io

cargo:<name>

cargo:tokio

alias for crates

owner/repo

vercel/ai

GitHub repo

owner/repo@ref

vercel/ai@v1.0.0

GitHub at ref

github:owner/repo

github:facebook/react

explicit GitHub

Storage

Sources are stored globally at ~/.local/share/opensrc/ (XDG compliant):

~/.local/share/opensrc/
├── sources.json           # Index of fetched sources
├── packages/              # npm/pypi/crates packages
│   └── zod/
│       ├── src/
│       ├── package.json
│       └── ...
└── repos/                 # GitHub repos
    └── github.com/
        └── vercel/
            └── ai/

Override with $OPENSRC_DIR or $XDG_DATA_HOME.

How It Works

  1. Agent calls execute tool with JS code: async () => opensrc.fetch("zod")

  2. Code runs in sandboxed vm context with injected opensrc API

  3. Server fetches package via opensrc (handles registry lookup, git clone)

  4. Only the result returns to agent context

┌─────────────────────────────────────────────────────────────┐
│                      Agent Context                          │
├─────────────────────────────────────────────────────────────┤
│  Tool call: execute({ code: "async () => opensrc.fetch..." })│
│                           ↓                                 │
│  Result: { success: true, source: { name: "zod", ... } }    │
└─────────────────────────────────────────────────────────────┘
                            ↕
┌─────────────────────────────────────────────────────────────┐
│                    opensrc-mcp Server                       │
├─────────────────────────────────────────────────────────────┤
│  Sandbox executes code with injected opensrc API            │
│  Full source tree stays here, never sent to agent           │
└─────────────────────────────────────────────────────────────┘

License

MIT

Available Tools

1 tool
executeB

Query and mutate fetched source code. Data stays server-side.

Types:

interface Source { type: "npm" | "pypi" | "crates" | "repo"; name: string; version?: string; ref?: string; path: string; fetchedAt: string; repository: string; }

interface FileEntry { path: string; size: number; isDirectory: boolean; }

interface TreeNode { name: string; type: "file" | "dir"; children?: TreeNode[]; }

interface GrepResult { source: string; file: string; line: number; content: string; }

interface AstGrepMatch { file: string; line: number; column: number; text: string; metavars: Record<string, string>; // captured $VAR values }

interface ParsedSpec { type: "npm" | "pypi" | "crates" | "repo"; name: string; version?: string; ref?: string; repoUrl?: string; }

interface FetchedSource { source: Source; alreadyExists: boolean; }

interface RemoveResult { success: boolean; removed: string[]; }

declare const sources: Source[]; declare const cwd: string;

declare const opensrc: { // Read operations list(): Source[]; has(name: string, version?: string): boolean; get(name: string): Source | undefined; files(sourceName: string, glob?: string): Promise<FileEntry[]>; tree(sourceName: string, options?: { depth?: number }): Promise; grep(pattern: string, options?: { sources?: string[]; include?: string; maxResults?: number; }): Promise<GrepResult[]>; astGrep(sourceName: string, pattern: string, options?: { glob?: string; lang?: string | string[]; limit?: number; }): Promise<AstGrepMatch[]>; read(sourceName: string, filePath: string): Promise; readMany(sourceName: string, paths: string[]): Promise<Record<string, string>>; resolve(spec: string): Promise;

// Mutation operations fetch(specs: string | string[], options?: { modify?: boolean; }): Promise<FetchedSource[]>; remove(names: string[]): Promise; clean(options?: { packages?: boolean; repos?: boolean; npm?: boolean; pypi?: boolean; crates?: boolean; }): Promise; };

Fetch spec formats (input to opensrc.fetch):

  • zod -> npm package (latest or lockfile version)

  • zod@3.22.0 -> npm specific version

  • pypi:requests -> Python/PyPI package

  • crates:serde -> Rust/crates.io package

  • vercel/ai -> GitHub repo (default branch)

  • vercel/ai@v3.0.0 -> GitHub repo at tag/branch/commit

Source names (returned in FetchedSource.source.name, used for read/grep):

  • npm packages: "zod", "drizzle-orm", "@tanstack/react-query"

  • pypi packages: "requests", "numpy"

  • crates: "serde", "tokio"

  • GitHub repos: "github.com/vercel/ai", "github.com/anthropics/sdk"

IMPORTANT: After fetching, always use source.name for subsequent API calls.

Examples:

// List all fetched sources async () => { return opensrc.list().map(s => ({ name: s.name, type: s.type, version: s.version || s.ref })); }

// Fetch and explore structure with tree() async () => { const [{ source }] = await opensrc.fetch("zod"); return await opensrc.tree(source.name, { depth: 2 }); }

// Fetch a GitHub repo and read key files async () => { const [{ source }] = await opensrc.fetch("vercel/ai"); const files = await opensrc.readMany(source.name, [ "package.json", "README.md", "src/index.ts" ]); return { sourceName: source.name, files: Object.keys(files) }; }

// readMany with globs async () => { return await opensrc.readMany("zod", ["packages/*/package.json"]); }

// Fetch multiple packages async () => { const results = await opensrc.fetch(["zod", "drizzle-orm", "hono"]); return results.map(r => r.source.name); }

// Text search with grep async () => { const results = await opensrc.grep("export function parse", { sources: ["zod"], include: "*.ts" }); if (matches.length === 0) return "No matches"; const { source, file, line } = matches[0]; const content = await opensrc.read(source, file); return content.split("\n").slice(line - 1, line + 29).join("\n"); }

// Search across all sources async () => { const results = await opensrc.grep("throw new Error", { include: "*.ts", maxResults: 20 }); return results.map(r => ${r.source}:${r.file}:${r.line}); }

// AST search with astGrep (use $VAR for single node, $$$VAR for multiple) // Patterns: "function $NAME($$$)" | "const $X = $Y" | "useState($INIT)" | "$OBJ.$METHOD($$$)" async () => { const matches = await opensrc.astGrep("zod", "function $NAME($$$ARGS)", { glob: "**/*.ts", limit: 10 }); return matches.map(m => ({ file: m.file, name: m.metavars.NAME, line: m.line })); }

// Find entry points async () => { const files = await opensrc.files("github.com/vercel/ai", "**/{index,main}.{ts,js}"); if (files.length > 0) return await opensrc.read("github.com/vercel/ai", files[0].path); return "No entry point found"; }

// Batch read with error handling async () => { const files = await opensrc.readMany("zod", ["src/index.ts", "src/types.ts", "nonexistent.ts"]); // Failed reads have "[Error: ...]" as value return Object.keys(files).filter(p => !files[p].startsWith("[Error:")); }

// Remove sources async () => { return await opensrc.remove(["zod", "github.com/vercel/ai"]); }

Inputs: code (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 1 tool

    Disambiguation5/5

    With only one tool, there is no possibility of confusion between tools. The single tool encompasses a well-defined API, and its purpose is clearly described in the description.

    Naming Consistency5/5

    The server has a single tool named 'execute', which is consistent in itself. While the name is generic, there are no other tools to compare against, so no naming inconsistencies exist.

    Tool Count2/5

    The domain covers fetching, searching, reading, and managing source code from multiple ecosystems, which is a broad scope. Exposing all of this through a single monolithic tool is overly condensed; separate tools for distinct operations (e.g., fetch, read, grep) would be more appropriate for agent discoverability.

    Completeness4/5

    The tool covers listing, fetching, reading, searching (grep and astGrep), and removal of sources, which is comprehensive for exploration. However, it lacks explicit update/edit capabilities for source files and no direct way to modify code, leaving a minor gap in mutation workflows.

    Maintenance

    ActivityInactive
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Agent-safe code retrieval MCP server that indexes repositories and provides semantic search, file navigation, call graph analysis, and bounded file reading tools for coding agents.
      7,358,368 npm
      3
      AGPL 3.0
    • A
      license
      Not graded
      quality
      C
      maintenance
      A local MCP server that indexes TypeScript/JavaScript projects and returns budget-aware, dependency-optimized context packs for AI coding assistants.
      1
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      A local MCP server that parses codebases into semantic chunks, indexes them in SQLite with vector embeddings, and exposes MCP tools for LLM agents to query.
      MIT