mcp

package
v0.31.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 3, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package mcp gives memcode an MCP (Model Context Protocol) client: it discovers the servers configured across scopes (local / project / user), connects to them (stdio, streamable HTTP, or SSE), lists their tools, and exposes a single Call entrypoint. This is the same mechanism Claude Code uses to gain third-party tools — and it follows Claude Code's documented model: project-scoped servers live in a checked-in .mcp.json and require explicit approval before use (see approvals.go), while servers you add yourself (local / user scope, in ~/.memcode/mcp.json) are trusted.

The protocol itself is spoken by the official SDK (github.com/modelcontextprotocol/go-sdk); this package handles config, scopes, approval, lifecycle, namespacing, and result flattening. The permission gate on each CALL lives in the runtime package (runtime/mcp.go).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddServer

func AddServer(root string, scope Scope, name string, sc ServerConfig) error

AddServer writes a server into the given scope's store (raw, unexpanded — secrets stay as ${VAR} references). Overwrites an existing entry of the same name in that scope.

func ApprovalsPath

func ApprovalsPath(root string) string

ApprovalsPath is where a project's MCP approval choices live: user-level state under the home directory (like UserStoreFile), keyed by a hash of the canonical project root so each project gets its own file. NEVER inside the repo — see the package header. Returns "" when no home directory can be determined.

func ConfigHash

func ConfigHash(cfg ServerConfig) string

ConfigHash is a stable digest of a server's RAW config (as read from its store, before ${VAR} expansion — see Resolve), so any edit to its .mcp.json entry invalidates a prior approval (re-prompting), while environment changes (which don't alter the committed config) do not — and resolved secrets never feed the hash.

func LocalServers

func LocalServers(root string) map[string]ServerConfig

LocalServers reads the raw local-scoped servers for this project from the user store.

func ProjectFile

func ProjectFile(root string) string

ProjectFile is the path to a project's checked-in MCP config.

func ProjectServers

func ProjectServers(root string) map[string]ServerConfig

ProjectServers reads the raw (unexpanded) project-scoped servers from <root>/.mcp.json.

func RememberCalls

func RememberCalls(root, name string, cfg ServerConfig, rawTool string) error

RememberCalls persists an invocation grant: rawTool == "" remembers the whole server ("Don't ask again for <server>"), otherwise the one tool ("Execute and remember"). For a local/user server this creates the record (those scopes are never connect-gated, so the record exists purely to carry grants); a stale-hash record is replaced, not merged.

func RemoveServer

func RemoveServer(root string, scope Scope, name string) (bool, error)

RemoveServer deletes a named server from a scope, reporting whether it existed.

func ResetApprovals

func ResetApprovals(root string) error

ResetApprovals clears all project-server choices (Claude Code's reset-project-choices). It also removes any legacy repo-resident file (ignored as a trust source, but stale).

func SaveApproval

func SaveApproval(root, name string, cfg ServerConfig, d Decision) error

SaveApproval records a decision for a project server, hashed against its current config. A same-config re-approve keeps any invocation grants; a rejection or config change drops them.

func ToolName

func ToolName(server, raw string) string

ToolName builds the model-facing name for a server's tool: mcp__<server>__<raw>. Both segments are sanitized to the function-name charset [A-Za-z0-9_] and the whole is capped at maxToolNameLen, so NO lane rejects the request over an odd or long server/tool name. The ORIGINAL raw name is preserved in Tool.Raw and used for the actual CallTool (see Call), so a sanitized/truncated model-facing name never changes which server tool runs. When sanitizing or truncating could make two distinct raw names collide, a short stable hash of the (server,raw) pair disambiguates — keeping byName keys unique. The clean, short common case is returned verbatim (Claude Code's scheme) so familiar names like mcp__supabase__execute_sql are unchanged.

func UserServers

func UserServers() map[string]ServerConfig

UserServers reads the raw user-scoped servers from the user store.

func UserStoreFile

func UserStoreFile() string

UserStoreFile is the path to the user-global MCP store (user + local scopes).

Types

type Approvals

type Approvals map[string]approvalRecord

Approvals is the persisted set of project-server choices for one project.

func LoadApprovals

func LoadApprovals(root string) Approvals

LoadApprovals reads the remembered choices (absent file → empty, not an error). Only the user-level store is consulted — a repo-committed approvals file grants nothing.

func (Approvals) CallAllowed

func (a Approvals) CallAllowed(name string, cfg ServerConfig, rawTool string) bool

CallAllowed reports whether invoking rawTool on the named server was remembered. False the moment the config hash stops matching — grants die with the config they were made against.

func (Approvals) Status

func (a Approvals) Status(name string, cfg ServerConfig) Decision

Status reports a project server's standing given the current config: "approved" only when a stored approval matches the live config hash; "rejected" when explicitly rejected (and still matching); otherwise "pending" (never decided, or the config changed since).

type Decision

type Decision string

Decision is a remembered approval choice for a project-scoped server.

const (
	Approved Decision = "approved"
	Rejected Decision = "rejected"
)

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager owns the live connections to all configured MCP servers and the merged tool catalog. A nil *Manager is valid and behaves as "no MCP" — all methods are safe to call.

func Connect

func Connect(ctx context.Context, servers map[string]ServerConfig, opts Options) *Manager

Connect connects to each given server (already resolved across scopes and filtered by approval policy — see Resolve and approvals.go), returning a Manager with the merged tool catalog. A server that fails to connect or list is skipped (recorded in Errors), never fatal — one broken server must not sink the session. Returns nil when the set is empty, so callers can treat "no MCP" as the zero case.

func (*Manager) Add

func (m *Manager) Add(ctx context.Context, servers map[string]ServerConfig, opts Options)

Add connects additional servers into an existing manager and merges their tools — used when a project server is approved mid-session. Safe on a nil receiver (returns it unchanged via the caller). Errors are appended to Errors(), never returned.

func (*Manager) Call

func (m *Manager) Call(ctx context.Context, name string, args map[string]any) (string, bool, error)

Call invokes a namespaced MCP tool and returns its flattened text, whether the tool reported an error, and any transport error.

func (*Manager) Close

func (m *Manager) Close()

Close tears down every connection. Safe on a nil Manager and idempotent.

func (*Manager) Errors

func (m *Manager) Errors() []error

Errors returns the per-server connect/list failures gathered during Connect.

func (*Manager) GetPrompt

func (m *Manager) GetPrompt(ctx context.Context, name string, args map[string]string) (string, error)

GetPrompt renders a namespaced prompt template with args, returning the flattened message text the model can use.

func (*Manager) Has

func (m *Manager) Has(name string) bool

Has reports whether name is a known MCP tool (used by the dispatcher to route a call).

func (*Manager) Lookup

func (m *Manager) Lookup(name string) (Tool, bool)

Lookup returns the catalog entry for a namespaced tool name.

func (*Manager) Prompts

func (m *Manager) Prompts() []Prompt

Prompts returns the merged prompt catalog across all connected servers.

func (*Manager) ReadResource

func (m *Manager) ReadResource(ctx context.Context, uri string) (string, error)

ReadResource fetches a resource's contents by uri, flattened to text.

func (*Manager) Resources

func (m *Manager) Resources() []Resource

Resources returns the merged resource catalog across all connected servers.

func (*Manager) Tools

func (m *Manager) Tools() []Tool

Tools returns the merged, namespaced tool catalog across all connected servers.

type Options

type Options struct {
	Version    string // memcode version reported to servers
	AllowOAuth bool   // attach the interactive OAuth flow to remote servers that need auth (interactive sessions only)
}

Options configure a connection batch.

type Prompt

type Prompt struct {
	Name        string // namespaced
	Server      string
	Raw         string
	Description string
	Arguments   []PromptArg
}

Prompt is one reusable MCP prompt template a server exposes. Name is namespaced (mcp__<server>__<raw>) for the catalog; the raw name is used with GetPrompt.

type PromptArg

type PromptArg struct {
	Name        string
	Description string
	Required    bool
}

PromptArg describes one argument a prompt template accepts.

type Resource

type Resource struct {
	URI         string // the server's resource uri (what ReadResource takes)
	Server      string
	Name        string
	Description string
	MIMEType    string
}

Resource is one MCP resource exposed by a server — external context (a doc, a schema, a runbook) the model can READ by uri. Namespaced like tools so servers can't collide.

type Scope

type Scope string

Scope is where a server is configured, mirroring Claude Code's three scopes.

const (
	// ScopeLocal is private to you in ONE project (stored in ~/.memcode/mcp.json under the
	// project path). Trusted — you added it.
	ScopeLocal Scope = "local"
	// ScopeProject is shared with the team via a checked-in <root>/.mcp.json. UNTRUSTED until
	// approved (see approvals.go) — it's repo content that could come from anyone.
	ScopeProject Scope = "project"
	// ScopeUser is available across all your projects (stored in ~/.memcode/mcp.json). Trusted.
	ScopeUser Scope = "user"
)

type ScopedServer

type ScopedServer struct {
	Name   string
	Scope  Scope
	Config ServerConfig // raw (unexpanded); ExpandServer before connecting
}

ScopedServer is a server resolved with the scope that won it. Config is the RAW entry as stored (${VAR} references intact): approvals and invocation grants hash the raw config (see approvals.ConfigHash), so env changes never invalidate them and resolved secrets never feed the hash. Expand with ExpandServer at connect time.

func Resolve

func Resolve(root string) []ScopedServer

Resolve returns every configured server merged across scopes with Claude Code's precedence (local > project > user, matched by name; the whole winning entry is used, never merged), each RAW (unexpanded) and tagged with its scope. The caller applies approval policy (project scope) against the raw config and calls ExpandServer only on what it actually connects.

type ServerConfig

type ServerConfig struct {
	Type    string            `json:"type,omitempty"` // stdio | http | streamable-http | sse (inferred when empty)
	Command string            `json:"command,omitempty"`
	Args    []string          `json:"args,omitempty"`
	Env     map[string]string `json:"env,omitempty"`
	URL     string            `json:"url,omitempty"`
	Headers map[string]string `json:"headers,omitempty"`
	// HeadersHelper is an optional command run at connect time whose stdout supplies HTTP
	// headers (JSON object, or "Name: value" lines) — for tokens minted per connection rather
	// than stored in config. Merged over static Headers.
	HeadersHelper string `json:"headersHelper,omitempty"`
	// Timeout is a per-server tool-call timeout in milliseconds (overrides the default).
	Timeout int `json:"timeout,omitempty"`
	// Auth controls remote authentication: "" / "auto" attaches the interactive OAuth flow when
	// no static auth header is present; "oauth" forces it; "none" disables it.
	Auth string `json:"auth,omitempty"`
}

ServerConfig is one declared MCP server. A stdio server is launched as a subprocess (Command+Args+Env); an http/sse server is reached at URL with optional Headers.

func ExpandServer added in v0.27.0

func ExpandServer(sc ServerConfig) ServerConfig

ExpandServer expands ${VAR} / ${VAR:-default} in every string the config carries — so a secret like an access token lives in the environment, not committed in .mcp.json. Callers expand at CONNECT time only; approvals/grants always hash the raw config (ConfigHash).

func (ServerConfig) Transport

func (c ServerConfig) Transport() string

Transport returns the normalized transport (stdio | http | sse) for display/inspection.

type Tool

type Tool struct {
	Name        string         // namespaced for the model: mcp__<server>__<raw>
	Server      string         // declaring server name
	Raw         string         // original tool name on the server
	Description string         // server-provided description
	InputSchema map[string]any // JSON-schema object, ready for a tool definition
}

Tool is one discovered MCP tool, flattened for memcode's tool registry.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL