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"]); }

ParametersJSON Schema
NameRequiredDescriptionDefault
codeYesJavaScript async arrow function to execute

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description mentions that data stays server-side, which is a key behavioral trait. It also indicates the tool supports both query and mutation operations. However, without annotations, it lacks details on side effects, error handling, or resource limits. The extensive description of the opensrc API indirectly clarifies behavior but is not focused on the tool itself.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is excessively long, containing type definitions, a full API declare block, and many examples. While the first two sentences are front-loaded and clear, the rest is verbose and repetitive. Many details could be moved to reference documentation, making the tool description hard to parse quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is comprehensive about the environment (opensrc API) but lacks explicit information about the tool's return value, error handling, or execution context. Given the complexity of the runtime, the description covers the code execution environment well, but not the tool's own behavior completely. The output schema is absent, so some completeness is lost.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% coverage with a description for the only parameter ('code' as JavaScript async arrow function). The description adds value by providing extensive examples of valid code snippets, but it does not explain parameter semantics beyond what the schema already states. The baseline of 3 is appropriate since schema coverage is complete.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool queries and mutates fetched source code and that data stays server-side. This provides a clear verb+resource description, distinguishing the tool from hypothetical others that might expose data. However, the purpose could be slightly more specific about executing user-provided JavaScript code.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not explicitly state when to use this tool versus alternatives, but since there are no siblings, this is less critical. It provides examples of common use cases like fetching and exploring code, which imply usage. However, there is no guidance on when not to use it (e.g., for non-code tasks).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 1 tool updatev0.3.0
    • First observedexecute

TDQS

B3/5.0
Disambiguation1/5

There is only one tool named 'execute', so disambiguation is not applicable. However, the tool description indicates it handles both querying and mutating source code, which could be seen as combining multiple distinct operations into a single tool, potentially causing confusion about its scope.

Naming Consistency5/5

With only one tool, naming consistency is trivially perfect. The tool name 'execute' follows a clear verb pattern, and there are no other tools to cause inconsistency.

Tool Count2/5

The server has only one tool, which is too few for its apparent purpose of managing and analyzing source code across multiple ecosystems (npm, pypi, crates, repos). The tool 'execute' bundles many operations (list, fetch, read, grep, etc.), making the surface overly simplistic for the domain's complexity.

Completeness2/5

The tool surface is severely incomplete. While the underlying API (opensrc) provides comprehensive operations (e.g., list, fetch, read, grep, astGrep, remove), the MCP server exposes only a single 'execute' tool, forcing all functionality through one interface. This creates significant gaps in discoverability and usability, as agents cannot directly access specific operations like fetching or searching without interpreting the tool's description and examples.

Maintenance

ActivityInactive
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

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.
    3,448,419
    3
    AGPL 3.0
  • A
    license
    Not graded
    quality
    B
    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
    C
    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

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dmmulroy/opensrc-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server