Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>stata-codeNew to Visual Studio Code? Get it now.
stata-code

stata-code

Bryce Wang

|
312 installs
| (0) | Free
Run Stata in VS Code via the agent-native stata-code MCP server: run cells & hierarchical sections, a Stata-free .dta data viewer that keeps variable labels, value labels, formats and notes, an agent-native Variables window, a sidebar for sessions/data/outputs/logs/graphs, typed-error diagnostics, a
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

stata-code — VSCode extension

Run Stata code from VSCode through the agent-native stata-code MCP server.

Status: v0.12 (July 2026). Full UI surface — orange Stata title-bar buttons, editor context menu, status bar with session/cancel actions, activity-bar sidebar with sessions / last result / data (variables) / run history / logs / graphs / outputs panels, syntax highlighting, outline/section navigation, code-lens cells and sections, inline error squigglies, graph webview Save/Open actions, run-bundle export, and Stata working-directory helpers. Source build with npm install && npm run compile.

What it does

A thin VSCode transport in front of the same stata-code-mcp server that Claude Code / Cursor use. The extension owns no Stata logic; everything goes through MCP stata_run, get_log, get_graph, get_matrix, list_sessions, cancel_session, reset_session.

Because it is a human-facing surface rather than an agent one, the extension requests include_results: "full" — matrices stay inline instead of becoming the matrix:// stubs the server returns by default, so the sidebar's matrix view has values to render. The Jupyter kernel does the same, for the same reason.

The Outputs panel draws on both of the server's artifact sources: the files a run wrote in its working directory (result.outputs, reported on every run since 0.11, shown with their size) and the archived copies inside a run bundle (log.files.output_paths, present only when persist_log_files was requested, labelled bundle). Working-directory files are listed first — that is the file you actually want to open.

UI surface

Editor

Affordance What it does
Orange toolbar buttons in editor title bar Run selection/current line, view data preview, stop, new tab, switch tab, restart, show output, and working-directory actions
Run button in editor title bar Run all / active file
Right-click menu → Stata: Run Selection / Run Active File / View Data Preview Same, from the editor
Right-click menu → Stata: Working Directory... Show or change Stata's current directory
Cmd/Ctrl+Enter or Cmd/Ctrl+D Run selection (or current line if no selection)
Cmd/Ctrl+Shift+Enter Run the current hierarchical section
Inline ▶ Run Cell code-lens above any * %% line Run that cell
Inline ▶ Run Section code-lens above **# headings Run from that heading to the next equal/higher heading
Outline view entries for **# headings and program define blocks Navigate long .do / .ado files
Completion Built-in commands, configured community commands, functions, variables from the last result, and variables inferred from the open document
F2 rename on recognized variables Rename variables across the current document while skipping comments and Stata commands
Red squiggle on the failing line After a failed run; hover to see the typed-error message and suggestions
Stata: View Data Preview Opens the data in the active session's memory in the data viewer (first stataCode.dataPreviewObs rows), with labels, formats and notes intact
Opening any *.dta file Shows it in the data viewer — no Stata needed (see below)

Data viewer for .dta files

Double-click a .dta file in the Explorer and it opens in a grid, the way Stata's Data Browser would show it. The file is read directly, from StataCorp's published format specification, so this works without Stata or Python installed and without the MCP server running.

Nothing in the file is lost on the way to the screen:

  • Variable labels sit under each column name, and in the variables panel.
  • Value labels replace the codes they stand for (1 → Married), in a distinct colour; untick Value labels to see the underlying numbers.
  • Display formats are honoured: %td / %tc / %tm / %tq dates (including custom ones such as %tdCCYY-NN-DD), %9.2f, %12.0gc, and so on print as Stata prints them.
  • Missing values stay distinct — ., .a … .z — and a value label on an extended missing value is applied.
  • Notes, the dataset label, the sort order and the save timestamp appear in the panel on the right; click a variable there to jump to its column and see its type, format, notes and full value-label mapping.
  • strL variables and non-ASCII text (UTF-8 in format 118+; auto-detected UTF-8 / GB18030 / Windows-1252 in older files) are decoded.

Observations are fixed-width records, so only the rows on screen are read: a multi-gigabyte file opens as fast as a small one. Go to row jumps anywhere; arrow keys, Page Up/Down and Home/End move the selection; Cmd/Ctrl+C copies the selected cell. If Stata re-saves the file while it is open, the viewer reloads.

Filter, sort, summarize. The bar under the title takes a Stata if expression and keeps the rows that satisfy it:

age > 60 & !missing(income)
region == "South":regionlbl
inlist(city, "Boston", "北京") | joined >= td(01jan2020)

It follows Stata's rules, not JavaScript's — a missing value is larger than every number (so age > 60 keeps missing ages, exactly as count if does), arithmetic on a missing value is missing, and comparing a string with a number is a type mismatch. The evaluator is tested against Stata 18's own count if on 80 expressions. Supported: the operators ! ~ ^ - * / + == != ~= < <= > >= & |, _n / _N, "text":labelname, and missing mi inlist inrange strpos regexm strmatch lower upper trim strlen ustrlen substr abs floor ceil int round mod min max sqrt exp ln log10 mdy td.

A variable can be named by any abbreviation only it starts with (gro for growth_flag); an ambiguous one is refused, as in Stata. On a dataset that was tsset or xtset, the time-series operators work too: L.sales, L2.sales, F.sales, D.sales, S12.sales, and runs such as L2D.sales. The lag is found by panel and time, whatever order the rows are saved in. Macros and operator lists (L(1/3).x) are not supported.

Hover a column header and click its arrow to sort (ascending, descending, off); Shift-click adds a secondary key. Sorting is by the underlying values with missing values last, as Stata's sort does, and ties keep their dataset order. The row-number gutter keeps showing each row's observation number in the file. Drag a header's right edge to resize the column; double-click it to fit.

Selecting a variable shows a summary of it over the rows in view — count, missing, distinct, mean, standard deviation, min, quartiles, max (equal to summarize, detail), and for categorical variables the most frequent values; click one to filter to it.

Copy and export. Drag, Shift-click or Shift-arrow to select a range; Cmd/Ctrl+C copies it as tab-separated text and Cmd/Ctrl+Shift+C includes the variable names. The Export menu writes:

  • the current view as CSV — filtered and sorted as shown, numbers at full precision rather than display precision, dates as dates, and value labels as text when Value labels is ticked;
  • the codebook — one row per variable with its type, format, value label, variable label and notes, plus a second file with every value-label mapping. This is the half of a dataset a CSV cannot carry.

Variable labels can be edited in place. Select a variable, click Edit beside its label in the details panel (or double-click the variable in the list), type, and press Enter; Esc cancels. The label is written straight into the file. Only that label's fixed-width field is overwritten, so the data, value labels, notes and formats keep their bytes, and no Stata is involved. Labels follow Stata's limit of 80 characters; files in formats older than 118 take ASCII only, since those formats do not say which encoding they use.

So can value labels and the dataset label. In a numeric variable's details the Value label list attaches any of the file's value labels, none, or a new one. Edit above the table of codes turns it into a list with one code label pair per line (a code is an integer or .a to .z); Save to file or Ctrl/Cmd+Enter replaces the whole set, which changes it for every variable that uses it. Drop removes a value label after asking and detaches it from the variables that used it. The dataset label has its own Edit in the dataset details (shown when no variable is selected).

Many labels at once go through the codebook. Export codebook writes one row per variable; edit the label and value_label columns in a spreadsheet (and the codes in the _value_labels.csv beside it), then choose Import labels from a codebook CSV… in the same menu. The viewer shows how many labels would change and applies them as one edit. Only the name column is required: a column that is absent is left alone, and so is a variable or a value label the files do not mention.

Every edit shows what it did in the status bar with an Undo button, and the viewer keeps the last 50 edits to take back. Attaching a value label overwrites one fixed-width field in place. Changing a value label's contents or the dataset label changes the length of the file, so a new copy is written beside it and swapped in with one rename; a crash leaves either the old file or the new one. In both cases the observations, notes and formats are copied, never re-encoded. The data cells are not editable. Agents get the same operations in bulk through the set_variable_labels and set_value_labels MCP tools.

Load in Stata (also on the Explorer context menu of any .dta) runs use "<file>", clear in the current session, asking first if that session has unsaved changes.

Filtering, sorting and summaries read the whole column. They are bounded by memory, not by a row count: stataCode.dtaViewerMemoryMb (default 2048) is what they may hold at once. A filter keeps 4 bytes per matching row and a sort about 20 bytes per row, so the default sorts roughly 80 million rows. Past the limit a filter or sort stops and says how much it needed; a summary still gives the count, mean, standard deviation, minimum and maximum, and leaves out the percentiles. Browsing has no limit. A descending sort keeps missing values at the end, as gsort does.

Supported formats: 113, 114, 115 (Stata 8–12), 117 (Stata 13), 118 and 119 (Stata 14+), 120 and 121 (Stata 18 alias variables). Formats 102 to 111 (Stata 1 to 7) open read-only: they can be browsed, filtered, sorted and summarized, and their labels cannot be edited in place. To open a .dta as raw bytes instead, use Reopen Editor With….

View Data Preview uses the same viewer for data that is only in memory: it copies the first rows through a scratch frame into a temporary .dta (your frame, its sort order, c(filename) and c(changed) are untouched) and opens that. On Stata 15 or older, and with the console backend, it falls back to a text listing.

Custom keyboard shortcuts. All shortcuts can be changed with VS Code's Preferences: Open Keyboard Shortcuts command. Search for Stata: Run Selection / Current Line, click the pencil icon, and enter the preferred key combination. The command ID for editing keybindings.json directly is stataCode.runSelection. The built-in Cmd/Ctrl+D binding only applies while a Stata editor has focus; a user-defined shortcut takes precedence if another extension or VS Code command conflicts with it.

Cell convention. A line whose trimmed text is * %% (optionally followed by a title, e.g. * %% setup) marks the start of a cell. The marker line is a Stata comment, so plain Stata still runs the file unchanged. The cell ends at the next marker or EOF. This is the Stata analog of Python's # %% cells.

Section convention. Lines beginning with **#, **##, ..., **###### are hierarchical section headings. Running a section includes the heading comment line and stops before the next heading at the same or higher level. The Outline view shows the same hierarchy, with program define blocks nested under the section that contains them.

Status bar

A left-aligned $(database) Stata: <session> chip is always visible once the extension activates. Click it for a QuickPick with compact actions:

  • New Stata tab… / Switch tab… (live sessions + locally-known "not started" tabs, plus New tab…)
  • View data preview (first stataCode.dataPreviewObs rows, in the data viewer)
  • Export latest run / Open latest log / Show latest graphs
  • Working directory… / Show output channel
  • Cancel <sid> / Reset <sid> / Close tab <sid>

While a run is in flight, the icon swaps to $(sync~spin) and the notification toast has a Cancel button (cooperative cancellation via the MCP cancel_session tool).

Activity bar sidebar

A new entry on the activity bar opens a sidebar with seven sections:

  • Sessions — live list_sessions view with the current session highlighted; header buttons for New / Refresh and per-item actions for Switch / Cancel / Reset / Close. Sessions you've used in this workspace but that aren't currently live still appear as "not started".
  • Last Result — collapsible groups for r() / e() returns, matrices, warnings, dataset summary (with variable list), a clickable log leaf (opens the run's full log via get_log(ref)), a clickable graphs leaf, and on failure a typed error block with the failing line and suggestions. Matrix entries open on demand via get_matrix(ref) as TSV text.
  • Data — a persistent variables browser for the dataset currently in memory: a summary row (N obs × K vars, frame, and a "modified" flag) followed by one row per variable, each with a type-aware icon (numeric vs string), its variable label as the description, and a tooltip with the full name · type · label. A display format that is not the storage type's default (%td, %9.2f) and an attached value label ([origin]) are shown too. Click a variable to copy its name; use the title-bar buttons to open the full data preview or refresh. The view tracks the last run, so it updates as the data changes — the agent-native equivalent of Stata's Variables window.
  • Run History — recent runs (capped at 64). Each item can rerun the exact submitted code, copy the code, open the JSON result, or export a reproducible run bundle.
  • Logs — recent runs (capped at 64) tagged with success/failure and line count; click to open the full log in an editor pane, or save it from the item context menu.
  • Graphs — every captured graph in reverse-chronological order (capped at 64); click any item to open it in the graph webview, or save it directly from the item context menu.
  • Outputs — table and export artifacts written during your runs (esttab/outreg2 tables, export delimited/export excel files, saved .dta, figures exported to disk), newest-first with a format-aware icon and file size. Click to open the file, or reveal it in Finder/Explorer from the item context menu. Since 0.12 this is populated on every run from result.outputs — the files written in the working directory — and no longer needs run-bundle logging. When persist_log_files=true is also on (as the method-workflow MCP prompts set it), the bundle's archived copies appear too, tagged bundle and listed after the working-directory originals.

Run bundles

Any run in Run History can be exported to a folder:

stata-run-20260507T213000Z-abc123/
  code.do
  log.txt
  result.json
  manifest.json
  graphs/
    01-scatter.png

This is intentionally simple: it captures exactly what was submitted and what came back, without turning the extension into a notebook system.

Working directory

Stata: Working Directory... offers four focused actions:

  • show current Stata pwd
  • cd to the workspace folder
  • cd to the current file's folder
  • choose a folder with VS Code's native picker

These utility commands run in the active Stata session but do not add noise to Run History / Logs / Graphs.

Graph webview

Successful runs with one or more graphs auto-open a side webview that fetches each graph's bytes via get_graph(ref) lazily. v0.2 adds:

  • Per-graph Save as… button → native save dialog → writes PNG / SVG / PDF
  • Per-graph Open externally button → writes to OS temp + opens with the default app
  • Per-graph collapsible result block for hiding old figures while comparing
  • Top-level Refresh button → re-fetches the current panel

The webview uses a strict CSP with a per-render nonce. Graph bytes never leave the local pystata / MCP boundary.

Setup

cd vscode
npm install
npm run compile

For local development, open this vscode/ folder in VSCode and F5 to launch an Extension Development Host. The first command invocation spawns stata-code-mcp lazily (one process per workspace). Make sure stata-code-mcp is on PATH or override. The extension also expands common macOS Python script directories (~/.local/bin, Homebrew, and ~/Library/Python/*/bin) before spawning, and falls back to workspace .venv / venv interpreters, stataCode.pythonPath, the Python extension interpreter, and system python3 -m stata_code.mcp when the default console script cannot be found.

// settings.json
{
  "stataCode.serverCommand": "/abs/path/to/python",
  "stataCode.serverArgs": ["-m", "stata_code.mcp"]
}

To diagnose PATH or virtualenv mismatches without launching Stata, run the read-only package doctor in the Python environment the extension should use:

stata-code doctor --no-stata-probe

It reports whether stata-code-mcp is on PATH, whether the MCP extra is installed, where pystata would be discovered, which project/user MCP config files mention stata-code, and which absolute-path / python -m stata_code.mcp fallback is safest for GUI clients.

Configuration

Key Default Purpose
stataCode.serverCommand stata-code-mcp Command to spawn the MCP server
stataCode.serverArgs [] Extra args passed to the server process
stataCode.pythonPath "" Fallback Python interpreter for -m stata_code.mcp
stataCode.sessionId "main" Session id passed to stata_run (also driven by the status bar's Switch session…). Must match [A-Za-z0-9_-]+.
stataCode.dataPreviewObs 1000 Rows View data preview copies from memory into the data viewer (1–100000). Shorter datasets are shown in full. The text fallback is capped at 200 rows.
stataCode.dtaLegacyEncoding "auto" Text encoding for .dta formats older than 118, which predate UTF-8. auto tries UTF-8, then GB18030, then Windows-1252; set e.g. gbk, big5, shift_jis or windows-1252 to force one.
stataCode.includeFullLog false Inline full log instead of fetching via get_log(ref)
stataCode.persistLogFiles true Save file-backed runs as immutable log bundles next to the source file
stataCode.persistGeneratedFiles true Copy newly-created tables/exports and captured graphs into the run bundle
stataCode.useDoFileDirectory true cd Stata to the source .do file's directory before file-backed runs

TypeScript types

src/types/runResult.ts is the hand-rolled subset the extension consumes. The full machine-readable schema lives at ../schema/run_result.schema.json (generated from the Pydantic model by python scripts/export_schema.py in the repo root). To regenerate the full TypeScript types side-by-side as src/types/runResult.generated.ts:

npm run gen-types

Diff the two and pull in any newly-added fields by hand.

Architecture

VSCode editor / sidebar / status bar / webview
   │
   ▼  (high-level callTool)
StataMcpClient (src/mcpClient.ts)
   │
   ▼  (stdio JSON-RPC, MCP)
stata-code-mcp (Python subprocess)
   │
   ▼  (in-process)
pystata → Stata 17+

UI modules:

File Responsibility
src/extension.ts activation, command registration, run pipeline
src/mcpClient.ts MCP transport (stdio child process)
src/statusBar.ts status bar item + running-state spinner
src/treeProviders.ts sessions / last-result / data / run-history / logs / graphs / outputs sidebar trees
src/dataBrowser.ts variables-window data nodes for the Data view
src/outputs.ts table/export artifact nodes for the Outputs view
src/dtaReader.ts Stata-free .dta parser (formats 102–111 read-only, 113–115, 117–121), random-access row reads
src/webviewHarness.ts runs the viewer's page in headless Chrome against the real session (npm run test:webview)
src/dtaFormat.ts Stata display formats (%td, %9.2f, %12.0gc, …)
src/dtaFilter.ts Stata if expression evaluator for the row filter
src/dtaQuery.ts filter + sort row order, per-variable summary statistics
src/dtaExport.ts CSV, codebook and clipboard exports
src/dtaImport.ts Label edits read back from an edited codebook CSV
src/dtaWriter.ts in-place variable-label edits
src/dtaViewModel.ts shapes metadata and formatted row blocks for the viewer
src/dtaEditor.ts custom editor + in-memory snapshot panel
media/dtaViewer.{js,css} the viewer's virtual grid and variables panel
src/cellLens.ts * %% code-lens provider
src/diagnostics.ts inline error squigglies
src/graphPanel.ts graph webview (Save / Open / Refresh)

Status / planned polish

  • .do notebook editor (kept deliberately minimal in favor of code-lens cells)
  • Full paged/filterable dataset table view (the current button is a first-100-row preview)
  • Rich matrix formatting beyond TSV
  • Extension-host tests (planned)

License

MIT, same as the parent project.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft