Alvin Unreal 2 months ago
parent
commit
80c8c7c112
8 changed files with 152 additions and 5 deletions
  1. 69 4
      CODEREF.md
  2. 5 0
      src/config/schema.ts
  3. 14 1
      src/index.ts
  4. 10 0
      src/mcp/context7.ts
  5. 10 0
      src/mcp/grep-app.ts
  6. 24 0
      src/mcp/index.ts
  7. 7 0
      src/mcp/types.ts
  8. 13 0
      src/mcp/websearch.ts

+ 69 - 4
CODEREF.md

@@ -10,6 +10,7 @@ src/
 ├── cli/              # Installer CLI
 ├── config/           # Configuration loading & constants
 ├── features/         # Background task manager
+├── mcp/              # MCP server configurations
 ├── tools/            # Tool definitions (background_task, etc.)
 ├── utils/            # Shared utilities
 └── index.ts          # Plugin entry point
@@ -27,6 +28,7 @@ const OhMyOpenCodeLite: Plugin = async (ctx) => {
     name: "oh-my-opencode-lite",
     agent: agents,      // Agent configurations
     tool: tools,        // Custom tools
+    mcp: mcps,          // MCP server configs
     config: (cfg) => {} // Modify OpenCode config
   };
 };
@@ -70,7 +72,64 @@ export function createExampleAgent(model: string): AgentDefinition {
 3. Add to `AgentName` type in `src/config/schema.ts`
 4. Add default model in `src/config/schema.ts` → `DEFAULT_MODELS`
 
-### 3. Configuration
+### 3. MCP Servers
+
+**Location:** `src/mcp/`
+
+Built-in MCP servers enabled by default:
+
+| MCP | Purpose | URL |
+|-----|---------|-----|
+| `websearch` | Real-time web search via Exa AI | `https://mcp.exa.ai/mcp` |
+| `context7` | Official library documentation | `https://mcp.context7.com/mcp` |
+| `grep_app` | GitHub code search via grep.app | `https://mcp.grep.app` |
+
+**Files:**
+- `src/mcp/types.ts` - MCP type definitions
+- `src/mcp/websearch.ts` - Exa web search config
+- `src/mcp/context7.ts` - Context7 docs config
+- `src/mcp/grep-app.ts` - grep.app code search config
+- `src/mcp/index.ts` - Factory function
+
+**To add a new MCP:**
+
+```typescript
+// src/mcp/my-mcp.ts
+import type { RemoteMcpConfig } from "./types";
+
+export const my_mcp: RemoteMcpConfig = {
+  type: "remote",
+  url: "https://my-mcp-server.com/mcp",
+  enabled: true,
+  headers: process.env.MY_API_KEY
+    ? { "x-api-key": process.env.MY_API_KEY }
+    : undefined,
+};
+```
+
+```typescript
+// src/mcp/index.ts - add to allBuiltinMcps
+import { my_mcp } from "./my-mcp";
+
+const allBuiltinMcps: Record<McpName, RemoteMcpConfig> = {
+  // ...existing
+  my_mcp,
+};
+
+// src/mcp/types.ts - add to McpNameSchema
+export const McpNameSchema = z.enum(["websearch", "context7", "grep_app", "my_mcp"]);
+```
+
+**Disabling MCPs:**
+
+Users can disable MCPs in their config:
+```json
+{
+  "disabled_mcps": ["websearch"]
+}
+```
+
+### 4. Configuration
 
 **Files:**
 - `src/config/schema.ts` - Zod schemas & types
@@ -93,6 +152,7 @@ type AgentOverrideConfig = {
 type PluginConfig = {
   agents?: Record<string, AgentOverrideConfig>;
   disabled_agents?: string[];
+  disabled_mcps?: string[];
 };
 ```
 
@@ -100,7 +160,7 @@ type PluginConfig = {
 - User: `~/.config/opencode/oh-my-opencode-lite.json`
 - Project: `.opencode/oh-my-opencode-lite.json`
 
-### 4. Tools
+### 5. Tools
 
 **Location:** `src/tools/`
 
@@ -124,7 +184,7 @@ const my_tool = tool({
 });
 ```
 
-### 5. Background Tasks
+### 6. Background Tasks
 
 **Files:**
 - `src/features/background-manager.ts` - Task lifecycle management
@@ -277,6 +337,10 @@ import { MY_NEW_TIMEOUT_MS } from "../config";
 | `src/index.ts` | Plugin entry, exports |
 | `src/agents/index.ts` | Agent factory, override logic |
 | `src/agents/orchestrator.ts` | Main orchestrator agent |
+| `src/mcp/index.ts` | MCP factory, builtin MCPs |
+| `src/mcp/websearch.ts` | Exa AI web search |
+| `src/mcp/context7.ts` | Context7 docs lookup |
+| `src/mcp/grep-app.ts` | GitHub code search |
 | `src/config/schema.ts` | Types, Zod schemas, defaults |
 | `src/config/constants.ts` | Timeouts, intervals |
 | `src/config/loader.ts` | Config file loading |
@@ -296,7 +360,8 @@ import type { AgentConfig as SDKAgentConfig } from "@opencode-ai/sdk";
 
 // Local types
 import type { AgentDefinition } from "./agents";
-import type { PluginConfig, AgentOverrideConfig, AgentName } from "./config";
+import type { PluginConfig, AgentOverrideConfig, AgentName, McpName } from "./config";
+import type { RemoteMcpConfig } from "./mcp";
 ```
 
 ## Build & Test

+ 5 - 0
src/config/schema.ts

@@ -11,10 +11,15 @@ export const AgentOverrideConfigSchema = z.object({
 
 export type AgentOverrideConfig = z.infer<typeof AgentOverrideConfigSchema>;
 
+// MCP names
+export const McpNameSchema = z.enum(["websearch", "context7", "grep_app"]);
+export type McpName = z.infer<typeof McpNameSchema>;
+
 // Main plugin config
 export const PluginConfigSchema = z.object({
   agents: z.record(z.string(), AgentOverrideConfigSchema).optional(),
   disabled_agents: z.array(z.string()).optional(),
+  disabled_mcps: z.array(z.string()).optional(),
 });
 
 export type PluginConfig = z.infer<typeof PluginConfigSchema>;

+ 14 - 1
src/index.ts

@@ -3,12 +3,14 @@ import { getAgentConfigs } from "./agents";
 import { BackgroundTaskManager } from "./features";
 import { createBackgroundTools } from "./tools";
 import { loadPluginConfig } from "./config";
+import { createBuiltinMcps } from "./mcp";
 
 const OhMyOpenCodeLite: Plugin = async (ctx) => {
   const config = loadPluginConfig(ctx.directory);
   const agents = getAgentConfigs(config);
   const backgroundManager = new BackgroundTaskManager(ctx);
   const backgroundTools = createBackgroundTools(ctx, backgroundManager);
+  const mcps = createBuiltinMcps(config.disabled_mcps);
 
   return {
     name: "oh-my-opencode-lite",
@@ -17,6 +19,8 @@ const OhMyOpenCodeLite: Plugin = async (ctx) => {
 
     tool: backgroundTools,
 
+    mcp: mcps,
+
     config: async (opencodeConfig: Record<string, unknown>) => {
       (opencodeConfig as { default_agent?: string }).default_agent = "orchestrator";
 
@@ -26,10 +30,19 @@ const OhMyOpenCodeLite: Plugin = async (ctx) => {
       } else {
         Object.assign(configAgent, agents);
       }
+
+      // Merge MCP configs
+      const configMcp = opencodeConfig.mcp as Record<string, unknown> | undefined;
+      if (!configMcp) {
+        opencodeConfig.mcp = { ...mcps };
+      } else {
+        Object.assign(configMcp, mcps);
+      }
     },
   };
 };
 
 export default OhMyOpenCodeLite;
 
-export type { PluginConfig, AgentOverrideConfig, AgentName } from "./config";
+export type { PluginConfig, AgentOverrideConfig, AgentName, McpName } from "./config";
+export type { RemoteMcpConfig } from "./mcp";

+ 10 - 0
src/mcp/context7.ts

@@ -0,0 +1,10 @@
+import type { RemoteMcpConfig } from "./types";
+
+/**
+ * Context7 - official documentation lookup for libraries
+ * @see https://context7.com
+ */
+export const context7: RemoteMcpConfig = {
+  type: "remote",
+  url: "https://mcp.context7.com/mcp",
+};

+ 10 - 0
src/mcp/grep-app.ts

@@ -0,0 +1,10 @@
+import type { RemoteMcpConfig } from "./types";
+
+/**
+ * grep.app - ultra-fast code search across GitHub repositories
+ * @see https://grep.app
+ */
+export const grep_app: RemoteMcpConfig = {
+  type: "remote",
+  url: "https://mcp.grep.app",
+};

+ 24 - 0
src/mcp/index.ts

@@ -0,0 +1,24 @@
+import { websearch } from "./websearch";
+import { context7 } from "./context7";
+import { grep_app } from "./grep-app";
+import type { RemoteMcpConfig } from "./types";
+import type { McpName } from "../config";
+
+export type { RemoteMcpConfig } from "./types";
+
+const allBuiltinMcps: Record<McpName, RemoteMcpConfig> = {
+  websearch,
+  context7,
+  grep_app,
+};
+
+/**
+ * Creates MCP configurations, excluding disabled ones
+ */
+export function createBuiltinMcps(
+  disabledMcps: readonly string[] = []
+): Record<string, RemoteMcpConfig> {
+  return Object.fromEntries(
+    Object.entries(allBuiltinMcps).filter(([name]) => !disabledMcps.includes(name))
+  );
+}

+ 7 - 0
src/mcp/types.ts

@@ -0,0 +1,7 @@
+// MCP types - McpName is defined in config/schema.ts to avoid duplication
+
+export type RemoteMcpConfig = {
+  type: "remote";
+  url: string;
+  headers?: Record<string, string>;
+};

+ 13 - 0
src/mcp/websearch.ts

@@ -0,0 +1,13 @@
+import type { RemoteMcpConfig } from "./types";
+
+/**
+ * Exa AI web search - real-time web search
+ * @see https://exa.ai
+ */
+export const websearch: RemoteMcpConfig = {
+  type: "remote",
+  url: "https://mcp.exa.ai/mcp?tools=web_search_exa",
+  headers: process.env.EXA_API_KEY
+    ? { "x-api-key": process.env.EXA_API_KEY }
+    : undefined,
+};