@letta-ai/letta-code 0.14.8 → 0.14.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/letta.js CHANGED
@@ -3127,7 +3127,7 @@ var package_default;
3127
3127
  var init_package = __esm(() => {
3128
3128
  package_default = {
3129
3129
  name: "@letta-ai/letta-code",
3130
- version: "0.14.8",
3130
+ version: "0.14.9",
3131
3131
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
3132
3132
  type: "module",
3133
3133
  bin: {
@@ -3589,7 +3589,7 @@ class SettingsManager {
3589
3589
  }
3590
3590
  this.settings = updatedSettings;
3591
3591
  await this.persistSettings();
3592
- console.log("Successfully migrated tokens to secrets");
3592
+ debugWarn("settings", "Successfully migrated tokens to secrets");
3593
3593
  } catch (error) {
3594
3594
  console.warn("Failed to migrate tokens to secrets:", error);
3595
3595
  console.warn("Tokens will remain in settings file for persistence");
@@ -30640,11 +30640,22 @@ var import_react16, useInput = (inputHandler, options = {}) => {
30640
30640
  }
30641
30641
  let keypress = parse_keypress_default(data);
30642
30642
  if (!keypress.name && typeof data === "string") {
30643
+ let keycode = null;
30644
+ let modifier = 0;
30645
+ let event = 1;
30643
30646
  const csiUMatch = data.match(/^\x1b\[(\d+)(?:;(\d+))?(?::(\d+))?u$/);
30644
30647
  if (csiUMatch) {
30645
- const keycode = parseInt(csiUMatch[1], 10);
30646
- const modifier = parseInt(csiUMatch[2] || "1", 10) - 1;
30647
- const event = csiUMatch[3] ? parseInt(csiUMatch[3], 10) : 1;
30648
+ keycode = parseInt(csiUMatch[1], 10);
30649
+ modifier = parseInt(csiUMatch[2] || "1", 10) - 1;
30650
+ event = csiUMatch[3] ? parseInt(csiUMatch[3], 10) : 1;
30651
+ } else {
30652
+ const modifyOtherKeysMatch = data.match(/^\x1b\[27;(\d+);(\d+)~$/);
30653
+ if (modifyOtherKeysMatch) {
30654
+ modifier = parseInt(modifyOtherKeysMatch[1], 10) - 1;
30655
+ keycode = parseInt(modifyOtherKeysMatch[2], 10);
30656
+ }
30657
+ }
30658
+ if (keycode !== null) {
30648
30659
  if (event === 3) {
30649
30660
  return;
30650
30661
  }
@@ -30680,7 +30691,7 @@ var import_react16, useInput = (inputHandler, options = {}) => {
30680
30691
  rightArrow: keypress.name === "right",
30681
30692
  pageDown: keypress.name === "pagedown",
30682
30693
  pageUp: keypress.name === "pageup",
30683
- return: keypress.name === "return",
30694
+ return: keypress.name === "return" || keypress.name === "enter",
30684
30695
  escape: keypress.name === "escape",
30685
30696
  ctrl: keypress.ctrl,
30686
30697
  shift: keypress.shift,
@@ -64856,6 +64867,8 @@ In headless mode, use:
64856
64867
  settingsManager.setMemfsEnabled(agent.id, false);
64857
64868
  } else if (isNewlyCreatedAgent && !isSubagent) {
64858
64869
  settingsManager.setMemfsEnabled(agent.id, true);
64870
+ } else if (specifiedAgentId && !isSubagent) {
64871
+ settingsManager.setMemfsEnabled(agent.id, true);
64859
64872
  }
64860
64873
  if (settingsManager.isMemfsEnabled(agent.id)) {
64861
64874
  try {
@@ -65699,6 +65712,8 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
65699
65712
  const buffers = createBuffers(agent.id);
65700
65713
  const startTime = performance.now();
65701
65714
  let numTurns = 0;
65715
+ let lastStopReason = null;
65716
+ let sawStreamError = false;
65702
65717
  let currentInput = [
65703
65718
  { role: "user", content: userContent }
65704
65719
  ];
@@ -65710,7 +65725,33 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
65710
65725
  const stream2 = await sendMessageStream(conversationId, currentInput, {
65711
65726
  agentId: agent.id
65712
65727
  });
65713
- const streamJsonHook = ({ chunk, shouldOutput }) => {
65728
+ const streamJsonHook = ({
65729
+ chunk,
65730
+ shouldOutput,
65731
+ errorInfo
65732
+ }) => {
65733
+ if (errorInfo && shouldOutput) {
65734
+ sawStreamError = true;
65735
+ const errorEvent = {
65736
+ type: "error",
65737
+ message: errorInfo.message,
65738
+ stop_reason: "error",
65739
+ run_id: errorInfo.run_id,
65740
+ session_id: sessionId,
65741
+ uuid: crypto.randomUUID(),
65742
+ ...errorInfo.error_type && errorInfo.run_id && {
65743
+ api_error: {
65744
+ message_type: "error_message",
65745
+ message: errorInfo.message,
65746
+ error_type: errorInfo.error_type,
65747
+ detail: errorInfo.detail,
65748
+ run_id: errorInfo.run_id
65749
+ }
65750
+ }
65751
+ };
65752
+ console.log(JSON.stringify(errorEvent));
65753
+ return { shouldAccumulate: true };
65754
+ }
65714
65755
  if (!shouldOutput) {
65715
65756
  return { shouldAccumulate: true };
65716
65757
  }
@@ -65737,6 +65778,7 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
65737
65778
  };
65738
65779
  const result = await drainStreamWithResume(stream2, buffers, () => {}, currentAbortController?.signal, undefined, streamJsonHook);
65739
65780
  const stopReason = result.stopReason;
65781
+ lastStopReason = stopReason;
65740
65782
  const approvals = result.approvals || [];
65741
65783
  if (stopReason === "end_turn") {
65742
65784
  break;
@@ -65746,6 +65788,7 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
65746
65788
  }
65747
65789
  if (stopReason === "requires_approval") {
65748
65790
  if (approvals.length === 0) {
65791
+ lastStopReason = "error";
65749
65792
  break;
65750
65793
  }
65751
65794
  const { autoAllowed, autoDenied, needsUserInput } = await classifyApprovals(approvals, {
@@ -65835,9 +65878,12 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
65835
65878
  const lastReasoning = reversed.find((line2) => line2.kind === "reasoning" && ("text" in line2) && typeof line2.text === "string" && line2.text.trim().length > 0);
65836
65879
  const lastToolResult = reversed.find((line2) => line2.kind === "tool_call" && ("resultText" in line2) && typeof line2.resultText === "string" && (line2.resultText ?? "").trim().length > 0);
65837
65880
  const resultText = lastAssistant?.text || lastReasoning?.text || lastToolResult?.resultText || "";
65881
+ const isAborted = currentAbortController?.signal.aborted;
65882
+ const isError = sawStreamError || lastStopReason && lastStopReason !== "end_turn" && lastStopReason !== "requires_approval";
65883
+ const subtype = isAborted ? "interrupted" : isError ? "error" : "success";
65838
65884
  const resultMsg = {
65839
65885
  type: "result",
65840
- subtype: currentAbortController?.signal.aborted ? "interrupted" : "success",
65886
+ subtype,
65841
65887
  session_id: sessionId,
65842
65888
  duration_ms: Math.round(durationMs),
65843
65889
  duration_api_ms: 0,
@@ -65847,18 +65893,38 @@ async function runBidirectionalMode(agent, conversationId, _client, _outputForma
65847
65893
  conversation_id: conversationId,
65848
65894
  run_ids: [],
65849
65895
  usage: null,
65850
- uuid: `result-${agent.id}-${Date.now()}`
65896
+ uuid: `result-${agent.id}-${Date.now()}`,
65897
+ ...subtype === "error" && {
65898
+ stop_reason: lastStopReason && lastStopReason !== "end_turn" ? lastStopReason : "error"
65899
+ }
65851
65900
  };
65852
65901
  console.log(JSON.stringify(resultMsg));
65853
65902
  } catch (error) {
65903
+ const errorDetails = formatErrorDetails(error, agent.id);
65854
65904
  const errorMsg2 = {
65855
65905
  type: "error",
65856
- message: error instanceof Error ? error.message : "Unknown error occurred",
65906
+ message: errorDetails,
65857
65907
  stop_reason: "error",
65858
65908
  session_id: sessionId,
65859
65909
  uuid: crypto.randomUUID()
65860
65910
  };
65861
65911
  console.log(JSON.stringify(errorMsg2));
65912
+ const errorResultMsg = {
65913
+ type: "result",
65914
+ subtype: "error",
65915
+ session_id: sessionId,
65916
+ duration_ms: 0,
65917
+ duration_api_ms: 0,
65918
+ num_turns: 0,
65919
+ result: null,
65920
+ agent_id: agent.id,
65921
+ conversation_id: conversationId,
65922
+ run_ids: [],
65923
+ usage: null,
65924
+ uuid: `result-error-${agent.id}-${Date.now()}`,
65925
+ stop_reason: "error"
65926
+ };
65927
+ console.log(JSON.stringify(errorResultMsg));
65862
65928
  } finally {
65863
65929
  currentAbortController = null;
65864
65930
  }
@@ -69964,6 +70030,15 @@ var init_InlineBashApproval = __esm(async () => {
69964
70030
  }
69965
70031
  if (key.escape) {
69966
70032
  onCancel?.();
70033
+ return;
70034
+ }
70035
+ if (input === "1") {
70036
+ onApprove();
70037
+ return;
70038
+ }
70039
+ if (input === "2" && allowPersistence) {
70040
+ onApproveAlways("project");
70041
+ return;
69967
70042
  }
69968
70043
  }, { isActive: isFocused });
69969
70044
  const solidLine = SOLID_LINE6.repeat(Math.max(columns, 10));
@@ -70415,6 +70490,15 @@ var init_InlineFileEditApproval = __esm(async () => {
70415
70490
  }
70416
70491
  if (key.escape) {
70417
70492
  onCancel?.();
70493
+ return;
70494
+ }
70495
+ if (input === "1") {
70496
+ onApprove(diffsToPass.size > 0 ? diffsToPass : undefined);
70497
+ return;
70498
+ }
70499
+ if (input === "2" && allowPersistence) {
70500
+ onApproveAlways("project", diffsToPass.size > 0 ? diffsToPass : undefined);
70501
+ return;
70418
70502
  }
70419
70503
  }, { isActive: isFocused });
70420
70504
  const solidLine = SOLID_LINE8.repeat(Math.max(columns, 10));
@@ -70757,6 +70841,15 @@ var init_InlineGenericApproval = __esm(async () => {
70757
70841
  }
70758
70842
  if (key.escape) {
70759
70843
  onCancel?.();
70844
+ return;
70845
+ }
70846
+ if (input === "1") {
70847
+ onApprove();
70848
+ return;
70849
+ }
70850
+ if (input === "2" && allowPersistence) {
70851
+ onApproveAlways("project");
70852
+ return;
70760
70853
  }
70761
70854
  }, { isActive: isFocused });
70762
70855
  const solidLine = SOLID_LINE9.repeat(Math.max(columns, 10));
@@ -71350,6 +71443,15 @@ var init_InlineTaskApproval = __esm(async () => {
71350
71443
  }
71351
71444
  if (key.escape) {
71352
71445
  onCancel?.();
71446
+ return;
71447
+ }
71448
+ if (input === "1") {
71449
+ onApprove();
71450
+ return;
71451
+ }
71452
+ if (input === "2" && allowPersistence) {
71453
+ onApproveAlways("session");
71454
+ return;
71353
71455
  }
71354
71456
  }, { isActive: isFocused });
71355
71457
  const solidLine = SOLID_LINE11.repeat(Math.max(columns, 10));
@@ -71654,6 +71756,15 @@ var init_StaticPlanApproval = __esm(async () => {
71654
71756
  }
71655
71757
  if (key.escape) {
71656
71758
  onKeepPlanning("User cancelled");
71759
+ return;
71760
+ }
71761
+ if (input === "1") {
71762
+ onApproveAndAcceptEdits();
71763
+ return;
71764
+ }
71765
+ if (input === "2") {
71766
+ onApprove();
71767
+ return;
71657
71768
  }
71658
71769
  }, { isActive: isFocused });
71659
71770
  const hintText = isOnCustomOption ? customReason ? "Enter to submit · Esc to clear" : "Type feedback · Esc to cancel" : "Enter to select · Esc to cancel";
@@ -101358,7 +101469,7 @@ class SettingsManager2 {
101358
101469
  }
101359
101470
  this.settings = updatedSettings;
101360
101471
  await this.persistSettings();
101361
- console.log("Successfully migrated tokens to secrets");
101472
+ debugWarn("settings", "Successfully migrated tokens to secrets");
101362
101473
  } catch (error) {
101363
101474
  console.warn("Failed to migrate tokens to secrets:", error);
101364
101475
  console.warn("Tokens will remain in settings file for persistence");
@@ -103860,4 +103971,4 @@ Error during initialization: ${message}`);
103860
103971
  }
103861
103972
  main();
103862
103973
 
103863
- //# debugId=B1589B59DC2C974664756E2164756E21
103974
+ //# debugId=E6B9011D5A418C2E64756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letta-ai/letta-code",
3
- "version": "0.14.8",
3
+ "version": "0.14.9",
4
4
  "description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,171 @@
1
+ ---
2
+ name: converting-mcps-to-skills
3
+ description: Connect to MCP (Model Context Protocol) servers and create skills for repeated use. Load when a user wants to use an MCP server, connect to external tools via MCP, or when they mention MCP, model context protocol, or specific MCP servers.
4
+ ---
5
+
6
+ # Converting MCP Servers to Skills
7
+
8
+ Letta Code is not itself an MCP client, but as a general computer-use agent, you can easily connect to any MCP server using the scripts in this skill.
9
+
10
+ ## What is MCP?
11
+
12
+ MCP (Model Context Protocol) is a standard for exposing tools to AI agents. MCP servers provide tools via JSON-RPC, either over:
13
+ - **HTTP** - Server running at a URL (e.g., `http://localhost:3001/mcp`)
14
+ - **stdio** - Server runs as a subprocess, communicating via stdin/stdout
15
+
16
+ ## Quick Start: Connecting to an MCP Server
17
+
18
+ ### Step 1: Determine the transport type
19
+
20
+ Ask the user:
21
+ - Is it an HTTP server (has a URL)?
22
+ - Is it a stdio server (runs via command like `npx`, `node`, `python`)?
23
+
24
+ ### Step 2: Test the connection
25
+
26
+ **For HTTP servers:**
27
+ ```bash
28
+ npx tsx <skill-path>/scripts/mcp-http.ts <url> list-tools
29
+
30
+ # With auth header
31
+ npx tsx <skill-path>/scripts/mcp-http.ts <url> --header "Authorization: Bearer KEY" list-tools
32
+ ```
33
+
34
+ **For stdio servers:**
35
+ ```bash
36
+ # First, install dependencies (one time)
37
+ cd <skill-path>/scripts && npm install
38
+
39
+ # Then connect
40
+ npx tsx <skill-path>/scripts/mcp-stdio.ts "<command>" list-tools
41
+
42
+ # Examples
43
+ npx tsx <skill-path>/scripts/mcp-stdio.ts "npx -y @modelcontextprotocol/server-filesystem ." list-tools
44
+ npx tsx <skill-path>/scripts/mcp-stdio.ts "python server.py" list-tools
45
+ ```
46
+
47
+ ### Step 3: Explore available tools
48
+
49
+ ```bash
50
+ # List all tools
51
+ ... list-tools
52
+
53
+ # Get schema for a specific tool
54
+ ... info <tool-name>
55
+
56
+ # Test calling a tool
57
+ ... call <tool-name> '{"arg": "value"}'
58
+ ```
59
+
60
+ ## Creating a Dedicated Skill
61
+
62
+ When an MCP server will be used repeatedly, create a dedicated skill for it. This makes future use easier and documents the server's capabilities.
63
+
64
+ ### Decision: Simple vs Rich Skill
65
+
66
+ **Simple skill** (just SKILL.md):
67
+ - Good for straightforward servers
68
+ - Documents how to use the parent skill's scripts with this specific server
69
+ - No additional scripts needed
70
+
71
+ **Rich skill** (SKILL.md + scripts/):
72
+ - Good for frequently-used servers
73
+ - Includes convenience wrapper scripts with defaults baked in
74
+ - Provides a simpler interface than the generic scripts
75
+
76
+ See `references/skill-templates.md` for templates.
77
+
78
+ ## Built-in Scripts Reference
79
+
80
+ ### mcp-http.ts - HTTP Transport
81
+
82
+ Connects to MCP servers over HTTP. No dependencies required.
83
+
84
+ ```bash
85
+ npx tsx mcp-http.ts <url> [options] <command> [args]
86
+
87
+ Commands:
88
+ list-tools List available tools
89
+ list-resources List available resources
90
+ info <tool> Show tool schema
91
+ call <tool> '<json>' Call a tool
92
+
93
+ Options:
94
+ --header "K: V" Add HTTP header (repeatable)
95
+ --timeout <ms> Request timeout (default: 30000)
96
+ ```
97
+
98
+ **Examples:**
99
+ ```bash
100
+ # Basic usage
101
+ npx tsx mcp-http.ts http://localhost:3001/mcp list-tools
102
+
103
+ # With authentication
104
+ npx tsx mcp-http.ts http://localhost:3001/mcp --header "Authorization: Bearer KEY" list-tools
105
+
106
+ # Call a tool
107
+ npx tsx mcp-http.ts http://localhost:3001/mcp call vault '{"action":"search","query":"notes"}'
108
+ ```
109
+
110
+ ### mcp-stdio.ts - stdio Transport
111
+
112
+ Connects to MCP servers that run as subprocesses. Requires npm install first.
113
+
114
+ ```bash
115
+ # One-time setup
116
+ cd <skill-path>/scripts && npm install
117
+
118
+ npx tsx mcp-stdio.ts "<command>" [options] <action> [args]
119
+
120
+ Actions:
121
+ list-tools List available tools
122
+ list-resources List available resources
123
+ info <tool> Show tool schema
124
+ call <tool> '<json>' Call a tool
125
+
126
+ Options:
127
+ --env "KEY=VALUE" Set environment variable (repeatable)
128
+ --cwd <path> Set working directory
129
+ --timeout <ms> Request timeout (default: 30000)
130
+ ```
131
+
132
+ **Examples:**
133
+ ```bash
134
+ # Filesystem server
135
+ npx tsx mcp-stdio.ts "npx -y @modelcontextprotocol/server-filesystem ." list-tools
136
+
137
+ # With environment variable
138
+ npx tsx mcp-stdio.ts "node server.js" --env "API_KEY=xxx" list-tools
139
+
140
+ # Call a tool
141
+ npx tsx mcp-stdio.ts "python server.py" call read_file '{"path":"./README.md"}'
142
+ ```
143
+
144
+ ## Common MCP Servers
145
+
146
+ Here are some well-known MCP servers:
147
+
148
+ | Server | Transport | Command/URL |
149
+ |--------|-----------|-------------|
150
+ | Filesystem | stdio | `npx -y @modelcontextprotocol/server-filesystem <path>` |
151
+ | GitHub | stdio | `npx -y @modelcontextprotocol/server-github` |
152
+ | Brave Search | stdio | `npx -y @modelcontextprotocol/server-brave-search` |
153
+ | obsidian-mcp-plugin | HTTP | `http://localhost:3001/mcp` |
154
+
155
+ ## Troubleshooting
156
+
157
+ **"Cannot connect" error:**
158
+ - For HTTP: Check the URL is correct and server is running
159
+ - For stdio: Check the command works when run directly in terminal
160
+
161
+ **"Authentication required" error:**
162
+ - Add `--header "Authorization: Bearer YOUR_KEY"` for HTTP
163
+ - Or `--env "API_KEY=xxx"` for stdio servers that need env vars
164
+
165
+ **stdio "npm install" error:**
166
+ - Run `cd <skill-path>/scripts && npm install` first
167
+ - The stdio client requires the MCP SDK
168
+
169
+ **Tool call fails:**
170
+ - Use `info <tool>` to see the expected input schema
171
+ - Ensure JSON arguments match the schema
@@ -0,0 +1,141 @@
1
+ # Skill Templates for MCP Servers
2
+
3
+ When to create a dedicated skill:
4
+ - **One-off use**: No skill needed - just use `converting-mcps-to-skills` scripts directly
5
+ - **Repeated use**: Create a self-contained skill with customized scripts
6
+
7
+ Skills should be self-contained per the [Agent Skills spec](https://agentskills.io/specification).
8
+
9
+ ## Naming Rules (from Agent Skills spec)
10
+
11
+ The `name` field must:
12
+ - Be lowercase letters, numbers, and hyphens only (`a-z`, `0-9`, `-`)
13
+ - Be 1-64 characters
14
+ - Not start or end with a hyphen
15
+ - Not contain consecutive hyphens (`--`)
16
+ - Match the parent directory name exactly
17
+
18
+ Examples: `using-github-mcp`, `mcp-filesystem`, `slack-mcp`
19
+
20
+ ## Skill Template
21
+
22
+ Use this template when creating a self-contained skill for an MCP server.
23
+
24
+ ### Directory Structure
25
+
26
+ ```
27
+ using-<server-name>/
28
+ ├── SKILL.md
29
+ └── scripts/
30
+ └── <server>.ts # Customized client (copied from converting-mcps-to-skills)
31
+ ```
32
+
33
+ ### SKILL.md Template
34
+
35
+ ```markdown
36
+ ---
37
+ name: using-<server-name>
38
+ description: <What the server does>. Use when <trigger conditions>.
39
+ # Optional fields:
40
+ # license: MIT
41
+ # compatibility: Requires network access to <service>
42
+ ---
43
+
44
+ # Using <Server Name>
45
+
46
+ <Brief description>
47
+
48
+ ## Prerequisites
49
+
50
+ - <Requirements>
51
+
52
+ ## Quick Start
53
+
54
+ ```bash
55
+ # Set API key (if needed)
56
+ export <SERVER>_API_KEY="your-key"
57
+
58
+ # List tools
59
+ npx tsx <skill-path>/scripts/<server>.ts list-tools
60
+
61
+ # Call a tool
62
+ npx tsx <skill-path>/scripts/<server>.ts call <tool> '{"arg":"value"}'
63
+ ```
64
+
65
+ ## Available Tools
66
+
67
+ <Document tools with examples>
68
+
69
+ ## Environment Variables
70
+
71
+ - `<SERVER>_API_KEY` - API key for authentication
72
+ - `<SERVER>_URL` - Override server URL (default: <default-url>)
73
+ ```
74
+
75
+ ### Script Template (scripts/<server>.ts)
76
+
77
+ Copy the HTTP client from `converting-mcps-to-skills/scripts/mcp-http.ts` (or `mcp-stdio.ts` for stdio servers) and customize:
78
+
79
+ 1. Set `DEFAULT_URL` to this server's URL
80
+ 2. Rename the API key env var (e.g., `GITHUB_MCP_KEY` instead of generic)
81
+ 3. Optionally simplify the CLI for common operations
82
+
83
+ The copied code is self-contained - no external dependencies for HTTP transport.
84
+
85
+ ```typescript
86
+ #!/usr/bin/env npx tsx
87
+ /**
88
+ * <Server Name> CLI - Self-contained MCP client
89
+ */
90
+
91
+ // Customize these for your server
92
+ const DEFAULT_URL = "<server-url>";
93
+ const API_KEY = process.env.<SERVER>_API_KEY;
94
+
95
+ // Copy the rest of mcp-http.ts here and adjust as needed
96
+ // ...
97
+ ```
98
+
99
+ ## Example: Self-Contained Filesystem Skill
100
+
101
+ A complete example of a self-contained skill for the MCP filesystem server:
102
+
103
+ ```
104
+ using-mcp-filesystem/
105
+ ├── SKILL.md
106
+ └── scripts/
107
+ └── filesystem.ts # Copied and customized from mcp-stdio.ts
108
+ ```
109
+
110
+ **SKILL.md:**
111
+ ```markdown
112
+ ---
113
+ name: using-mcp-filesystem
114
+ description: Access local filesystem via MCP. Use when user wants to read, write, or search files via MCP protocol.
115
+ ---
116
+
117
+ # Using MCP Filesystem Server
118
+
119
+ Access local files via the official MCP filesystem server.
120
+
121
+ ## Quick Start
122
+
123
+ ```bash
124
+ npx tsx <skill-path>/scripts/filesystem.ts list-tools
125
+ npx tsx <skill-path>/scripts/filesystem.ts call read_file '{"path":"./README.md"}'
126
+ ```
127
+
128
+ ## Available Tools
129
+
130
+ - `read_file` - Read file contents
131
+ - `write_file` - Write content to file
132
+ - `list_directory` - List directory contents
133
+ - `search_files` - Search for files by pattern
134
+ - `get_file_info` - Get file metadata
135
+ ```
136
+
137
+ **scripts/filesystem.ts:**
138
+ Copy `converting-mcps-to-skills/scripts/mcp-stdio.ts` and set the default command to:
139
+ ```typescript
140
+ const DEFAULT_COMMAND = "npx -y @modelcontextprotocol/server-filesystem .";
141
+ ```