Skip to content
AI Agents (MCP)

AI Agents (MCP)

lemmego/mcp serves your application’s own state to an AI coding agent over the Model Context Protocol, and installs the guidelines, skills and rules that give the agent context.

lemmego mcp:install

A project created by lemmego new already has the server registered. For an existing project, see Adding it to an existing project.

Start with these two tools

An agent editing your project cannot see the routing table, the live schema, the resolved configuration, the migration state or the logs, so it guesses. The costly guesses are about APIs: a call written against a function that does not exist survives until somebody compiles it.

Two tools address that directly, and they are worth naming in your agent’s instructions:

ToolWhat it gives the agent
module-apiThe real exported signatures of a lemmego module at the version your project pins, read from the compiled package
search-docsThe modules’ own READMEs, which are the authoritative specification for each module

The rest supply context about your running application.

All tools

NameNotes
module-apiReal exported signatures at the pinned version; pass a symbol for one declaration with its doc comment
search-docsSearch the module READMEs, returning the matching sections
app-infoGo version, environment, live database dialect, the driver chosen for each subsystem, every lemmego module and its resolved version
configResolved configuration, secrets withheld; one key or the whole tree
list-routesEvery registered route with method, resolved path, handler and middleware counts; filterable by method or path
absolute-urlA path turned absolute against the configured APP_URL
database-connectionsWhich database is actually connected, the DSN with credentials withheld, live pool statistics
database-schemaLive tables, or one table’s columns with types, nullability and defaults
database-queryOne statement. Read-only by default
migration-statusApplied migrations from schema_migrations, newest first
healthThe registered health checks and each result
read-log-entriesRecent log lines, filterable, from the most recently written file
last-errorThe most recent error-level entry
record-ruleFile a durable project rule under .ai/rules and rebuild its index

Not available

  • Code execution. Go has no eval, so there is no equivalent of a tinker tool.
  • Browser logs. These need a JavaScript shim in the page.
  • An HTTP transport. See Safety.

Safety

This is a local development tool.

stdio only. An MCP server on a port is an unauthenticated connection to your database for anything that can reach it. There is no HTTP transport and adding one is not a planned feature.

Read-only by default. database-query accepts only SELECT, WITH, SHOW, EXPLAIN, TABLE and VALUES, and only one statement per call.

The guard is an allowlist, not a denylist, because a denylist has to enumerate every way SQL can change something and will miss one — TRUNCATE, GRANT, COPY, VACUUM, REINDEX, CLUSTER, COMMENT, SECURITY LABEL, DO, CALL, REFRESH MATERIALIZED VIEW, and whatever the next server version adds. Getting that list wrong means an agent drops a table. Stacked statements are refused outright, because a head-only check would pass SELECT 1; DROP TABLE users.

To lift it:

&lemmegomcp.Provider{Options: []lemmegomcp.Option{lemmegomcp.WithWrites()}}

or lemmego run mcp:serve --allow-writes, which warns on stderr.

Secrets are withheld. Configuration is redacted by key pattern — password, secret, token, key, credential, salt, dsn and more — walking nested maps, because sql.connections.pgsql.password is where a password actually lives.

It also rewrites a credential found inside a value, which is the case a key-based rule alone gets wrong and is not hypothetical: DATABASE_URL is the standard name for a Postgres connection string, its name contains no secret-looking fragment, and its value contains the password. The host, user and database survive; the password does not.

Adding it to an existing project

lemmego new registers the provider for you. An existing project has nobody to do it — Go has no equivalent of Composer’s package auto-discovery — so there are two steps, and mcp:install tells you if either is missing.

go get github.com/lemmego/mcp

Then register it last in bootstrap/providers.go:

import lemmegomcp "github.com/lemmego/mcp"

func LoadProviders() []app.Provider {
    providers := []app.Provider{
        // ...everything else...
    }

    // A development tool: it serves this application's configuration and
    // database to whatever starts it.
    if config.MustEnv("APP_ENV", "development") != "production" {
        providers = append(providers, &lemmegomcp.Provider{})
    }

    return providers
}

Last, because it reports on everything the providers above it register — the routes, the connection, the session store, the health checks — and listed earlier it would resolve nothing.

Not in production, because it serves your configuration and database to whatever starts it. It is stdio-only, so this is not a hole being closed; it is a development tool, and a production binary should not carry a command that reads the database. Remove the guard if you want it everywhere.

Then lemmego mcp:install and restart your editor.

What mcp:install writes

FileContents
.mcp.json, .cursor/mcp.json, .codex/mcp.jsonhow to start the server
CLAUDE.md, AGENTS.md, .cursor/rules/lemmego.mdcalways-on guidelines, inside a marked block
.ai/skills/*/SKILL.mdon-demand skills, for the modules the project actually uses
.ai/rules/index.mdthe index recorded rules are filed into

Agents: claude-code, cursor, codex, copilot, windsurf. Narrow with --agent, and skip parts with --no-skills, --no-rules, --no-guidelines.

Only the marked block of a guideline file is replaced. CLAUDE.md is a file people write in by hand, so everything outside <!-- BEGIN lemmego-guidelines --> and its END survives, and reinstalling replaces the block rather than appending a second one.

An existing MCP config is merged, not replaced, because several agents share .mcp.json. A config that exists and cannot be parsed is left strictly alone and reported — it is your work, and discarding it to fix a syntax error is not the tool’s call.

Recorded rules are never overwritten. .ai/rules should be committed: those are your team’s decisions, unlike an agent’s own memory, which is personal and session-scoped. The generated config and guideline files can be gitignored.

Guidelines, skills and rules

Three layers, loaded at different times and costing different amounts:

LoadedHolds
Guidelinesupfront, every requestwhat an agent needs before it knows what it is doing
Skillson demanddetail for one domain
Rulesby glob, when editing a matching filedecisions about your application

Guidelines are kept short, because everything loaded upfront costs context on every single request.

Skills ship only for the modules your project depends on. Rules are recorded through the record-rule tool rather than written by hand, because the index agents consult is regenerated there — a rule file added manually is never discovered.

Troubleshooting

The server shows as failed, with a red cross

The configuration points at lemmego run mcp:serve and your project has no such command, which means the provider is not registered. Re-run lemmego mcp:install: it checks for the module and the provider and prints exactly what is missing. See Adding it to an existing project.

CONNECTION_CLOSED

Update the CLI:

go install github.com/lemmego/cli/cmd@latest

The server speaks over stdin, so it needs a CLI that forwards it — cli v0.5.5 or later. On an older CLI the server starts, reads EOF immediately, treats that as the client disconnecting and exits without writing anything, which the editor reports as a server that will not start.

Nothing may write to stdout but protocol frames

If you add a tool, remember that one stray fmt.Println corrupts the stream and the editor reports a server that will not start, saying nothing about the print. Use stderr.