Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 6 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
<br />
<br />

<a href="https://www.npmjs.com/package/txtcode-ai"><img src="https://img.shields.io/npm/v/txtcode?color=blue&style=for-the-badge" alt="npm version" /></a>
<a href="https://www.npmjs.com/package/txtcode-ai"><img src="https://img.shields.io/npm/v/txtcode-ai?color=blue&style=for-the-badge" alt="npm version" /></a>
&nbsp;
<a href="https://www.npmjs.com/package/txtcode-ai"><img src="https://img.shields.io/npm/dm/txtcode?style=for-the-badge" alt="downloads" /></a>
<a href="https://www.npmjs.com/package/txtcode-ai"><img src="https://img.shields.io/npm/dm/txtcode-ai?style=for-the-badge" alt="downloads" /></a>
&nbsp;
<a href="https://github.com/IMvision12/txtcode/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-green?style=for-the-badge" alt="license" /></a>
&nbsp;
Expand Down Expand Up @@ -70,10 +70,6 @@ Claude Code, Cursor CLI, OpenAI Codex, Gemini CLI, Kiro CLI, OpenCode, and Ollam

Terminal, process manager, git, file search, HTTP client, environment variables, network diagnostics, cron jobs, and system info all callable by the LLM.

### 18 MCP Servers

Connect GitHub, Brave Search, Puppeteer, PostgreSQL, MongoDB, Redis, Elasticsearch, AWS, GCP, Cloudflare, Vercel, Atlassian, Supabase, CircleCI, Postman, Stripe, ElevenLabs, and Kaggle as external tools via the Model Context Protocol.

### Session Logging

Per-session logs accessible from the TUI. Follow live, view by index, auto-pruned after 7 days.
Expand Down Expand Up @@ -125,9 +121,9 @@ docker run -it \
txtcode
```

| Flag | Purpose |
| :--- | :------ |
| `-v $(pwd):/workspace` | Mounts your project directory into the container |
| Flag | Purpose |
| :----------------------------- | :-------------------------------------------------- |
| `-v $(pwd):/workspace` | Mounts your project directory into the container |
| `-v ~/.txtcode:/root/.txtcode` | Persists config, session data, and logs across runs |

> **Note:** API keys are stored securely via your OS keychain when running natively. Inside Docker, txtcode uses an encrypted file-based fallback (`TXTCODE_DOCKER=1` is set automatically). You can also pass keys as environment variables with `-e`, e.g. `-e ANTHROPIC_API_KEY=sk-...`.
Expand Down Expand Up @@ -163,7 +159,7 @@ txtcode supports **9 LLM providers** for chat mode. Configure one or more during
| **HuggingFace** | _Discovered at runtime_ | Inference Providers API |
| **OpenRouter** | _Discovered at runtime_ | Unified API for 100+ models |

All providers support tool calling and LLM can invoke any built-in tool or connected MCP server.
All providers support tool calling and the LLM can invoke any built-in tool.

---

Expand Down Expand Up @@ -201,52 +197,6 @@ The primary LLM in chat mode has access to **9 built-in tools** that it can call

---

## 📟 MCP Servers

txtcode integrates with the **Model Context Protocol** to connect external tool servers. Configure during initial setup or later via **Configuration** &rarr; **Manage MCP Servers** in the TUI.

### Developer Tools

| Server | Transport | Description |
| :--------------- | :-------- | :-------------------------------------------------------- |
| **GitHub** | stdio | Repos, issues, PRs, code search, Actions |
| **Brave Search** | stdio | Web, image, video, and news search |
| **Puppeteer** | stdio | Browser automation, screenshots, form filling |
| **CircleCI** | stdio | Build logs, flaky tests, pipeline status, rerun workflows |
| **Postman** | stdio | Collections, workspaces, API specs, code generation |
| **Stripe** | stdio | Customers, payments, invoices, subscriptions, refunds |
| **ElevenLabs** | stdio | Text-to-speech, voice cloning, audio transcription |
| **Kaggle** | HTTP | Datasets, notebooks, competitions, models, benchmarks |

### Databases

| Server | Transport | Description |
| :---------------- | :-------- | :--------------------------------------------- |
| **PostgreSQL** | stdio | Read-only SQL queries and schema inspection |
| **MongoDB** | stdio | CRUD, indexes, vector search, Atlas management |
| **Redis** | stdio | Data structures, caching, vectors, pub/sub |
| **Elasticsearch** | stdio | Index management, search queries, cluster ops |
| **Supabase** | HTTP | Postgres, Auth, Storage, Edge Functions |

### Cloud

| Server | Transport | Description |
| :--------------- | :-------- | :------------------------------------------------- |
| **AWS** | stdio | S3, Lambda, EKS, CDK, CloudFormation, 60+ services |
| **Google Cloud** | HTTP | BigQuery, GKE, Compute, Storage, Firebase |
| **Cloudflare** | HTTP | Workers, R2, DNS, Zero Trust, 2500+ endpoints |
| **Vercel** | HTTP | Deployments, domains, env vars, logs |

### Productivity

| Server | Transport | Description |
| :------------ | :-------- | :------------------------------------------------ |
| **Atlassian** | HTTP | Jira issues, Confluence pages, Compass components |

> **stdio** = local process, **HTTP** = remote Streamable HTTP endpoint. You can also add custom MCP servers via **Configuration** &rarr; **Manage MCP Servers**.

---

## 💬 Chat Commands

Send these commands in any messaging app while connected:
Expand All @@ -272,7 +222,6 @@ To modify settings, select **Configuration** from the main menu. Options include
- Change Messaging Platform
- Change Coding CLI Type
- Change AI Provider
- Manage MCP Servers (add/remove/enable/disable)
- Change Project Path
- View Current Config

Expand Down Expand Up @@ -327,13 +276,4 @@ Verbose and debug output goes to the log file; the terminal shows only key statu

</details>

<details>
<summary><b>MCP server connection failures</b></summary>

- **stdio servers:** ensure the required npm package is installed (e.g. `npx @modelcontextprotocol/server-github`)
- **HTTP servers:** verify the token is correct via **Configuration** &rarr; **Manage MCP Servers**
- Check **View Logs** for specific error messages

</details>

---
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
"dependencies": {
"@anthropic-ai/sdk": "^0.74.0",
"@google/generative-ai": "^0.24.1",
"@modelcontextprotocol/sdk": "^1.27.1",
"@slack/bolt": "^4.6.0",
"@whiskeysockets/baileys": "^7.0.0-rc.9",
"botbuilder": "^4.23.3",
Expand Down
159 changes: 0 additions & 159 deletions src/cli/commands/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import makeWASocket, {
} from "@whiskeysockets/baileys";
import chalk from "chalk";
import qrcode from "qrcode-terminal";
import type { MCPServerEntry } from "../../shared/types";
import { setApiKey, setBotToken } from "../../utils/keychain";
import { loadMCPServersCatalog, type MCPCatalogServer } from "../../utils/mcp-catalog-loader";
import {
discoverHuggingFaceModels,
discoverOpenRouterModels,
Expand Down Expand Up @@ -571,8 +569,6 @@ export async function authCommand() {
console.log(chalk.green(`✅ Configured ${configuredProviders.length} provider(s)`));
console.log();

const mcpServerEntries = await configureMCPServers();

const platform = await showCenteredList({
message: "Select messaging platform: (Use arrow keys)",
choices: [
Expand Down Expand Up @@ -851,8 +847,6 @@ export async function authCommand() {
idePort: 3000,
authorizedUser: "",
configuredAt: new Date().toISOString(),

mcpServers: mcpServerEntries,
};

fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
Expand Down Expand Up @@ -884,14 +878,6 @@ export async function authCommand() {
console.log(chalk.white(` ${label}: ${provider.provider} (${provider.model})`));
});

if (mcpServerEntries.length > 0) {
console.log(chalk.cyan("\nMCP Servers:"));
mcpServerEntries.forEach((server) => {
const status = server.enabled ? chalk.green("enabled") : chalk.gray("disabled");
console.log(chalk.white(` ${server.id} (${server.transport}) - ${status}`));
});
}

console.log(
chalk.cyan("\nRun ") +
chalk.bold("txtcode") +
Expand All @@ -905,151 +891,6 @@ export async function authCommand() {
}
}

async function configureMCPServers(): Promise<MCPServerEntry[]> {
const catalog = loadMCPServersCatalog();
if (!catalog || catalog.servers.length === 0) {
return [];
}

console.log(chalk.cyan("MCP Servers (optional)"));
console.log();
console.log(
chalk.gray("Connect external tools to your AI provider (GitHub, databases, cloud, etc.)"),
);
console.log();

const categoryNames = catalog.categories as Record<string, string>;
const serversByCategory = new Map<string, MCPCatalogServer[]>();
for (const server of catalog.servers) {
const cat = server.category || "other";
if (!serversByCategory.has(cat)) {
serversByCategory.set(cat, []);
}
serversByCategory.get(cat)!.push(server);
}

const selectedServers: MCPCatalogServer[] = [];
const selectedIds = new Set<string>();

let continueSelecting = true;
while (continueSelecting) {
const choices: Array<{ name: string; value: string }> = [
{ name: "Configure later", value: "__SKIP__" },
];

if (selectedServers.length > 0) {
choices[0] = { name: `← Done (${selectedServers.length} selected)`, value: "__SKIP__" };
}

for (const [category, servers] of serversByCategory) {
const label = categoryNames[category] || category;
for (const server of servers) {
if (selectedIds.has(server.id)) {
continue;
}
const transportTag = server.transport === "http" ? " [remote]" : "";
choices.push({
name: `[${label}] ${server.name} - ${server.description}${transportTag}`,
value: server.id,
});
}
}

if (choices.length === 1) {
console.log(chalk.yellow("\nAll available MCP servers have been selected.\n"));
break;
}

const selected = await showCenteredList({
message:
selectedServers.length > 0
? `Add another MCP server: (Use arrow keys)`
: `Select MCP server to connect: (Use arrow keys)`,
choices,
pageSize: 10,
});

if (selected === "__SKIP__") {
if (selectedServers.length === 0) {
console.log();
console.log(
chalk.gray(
"You can configure MCP servers anytime from 'txtcode config' → 'Manage MCP Servers'.",
),
);
console.log();
}
continueSelecting = false;
break;
}

const server = catalog.servers.find((s) => s.id === selected);
if (!server) {
continue;
}

selectedIds.add(server.id);

if (server.requiresToken) {
console.log();
const token = await showCenteredInput({
message: server.tokenPrompt || `Enter token for ${server.name}:`,
password: true,
validate: (input) => input.length > 0 || "Token/credential is required",
});
await setBotToken(server.keychainKey, token);

if (server.additionalTokens) {
for (const additional of server.additionalTokens) {
console.log();
const additionalToken = await showCenteredInput({
message: additional.tokenPrompt,
password: !additional.tokenPrompt.toLowerCase().includes("region"),
validate: (input) => input.length > 0 || "This field is required",
});
await setBotToken(additional.keychainKey, additionalToken);
}
}
}

selectedServers.push(server);
console.log();
console.log(chalk.white(" Connected servers:"));
for (const s of selectedServers) {
console.log(chalk.green(` ✅ ${s.name}`));
}
console.log();
}

if (selectedServers.length > 0) {
console.log();
console.log(chalk.green(`✅ Configured ${selectedServers.length} MCP server(s)`));
console.log();
}

return selectedServers.map((server): MCPServerEntry => {
const entry: MCPServerEntry = {
id: server.id,
transport: server.transport,
enabled: true,
};

if (server.transport === "stdio") {
entry.command = server.command;
entry.args = server.args ? [...server.args] : undefined;

if (server.tokenIsArg && server.keychainKey) {
entry.args = entry.args || [];
entry.args.push(`__KEYCHAIN:${server.keychainKey}__`);
}
} else {
entry.url = server.url;
}

return entry;
});
}

export function loadConfig(): Record<string, unknown> | null {
if (!fs.existsSync(CONFIG_FILE)) {
return null;
Expand Down
Loading