programmatic-mcp
A meta MCP server that orchestrates other MCP servers by lazily connecting to them and exposing their tools as JavaScript libraries. It allows users to execute JavaScript code that programmatically interacts with multiple MCP servers within a unified environment.
README
jsmcp
jsmcp exists for cases where an agent needs to do more than a single MCP tool call.
Most MCP clients are great at one tool call at a time, but awkward when work requires:
- several related tool calls
- branching logic based on earlier results
- loops, retries, or result aggregation
- transforming tool output before the next call
jsmcp solves that by exposing approved MCP tools as JavaScript namespaces. Instead of forcing the model to juggle many separate tool invocations, it can discover what is available and then write a small amount of JavaScript to use those tools programmatically.
In practice, this means:
- the agent first learns what servers and tools are available, while
jsmcpconstrains access to whatever servers and tools you allow in a preset - the agent can then write JavaScript for multi-step work
- logs stay separate from return values so the code stays easier to reason about
Config is read from $XDG_CONFIG_HOME/jsmcp/ or, if XDG_CONFIG_HOME is not set, ~/.config/jsmcp/. Exactly one of config.json, config.yaml, or config.yml must exist there.
Why
Use jsmcp when you want agents to treat MCP tools more like a small programmable API surface than a sequence of isolated button presses.
This is especially useful when an agent needs to:
- combine results from several MCP tools
- script workflows across one or more MCP servers
- make decisions in code instead of repeatedly re-planning between tool calls
- keep tool access constrained to a reviewed preset
Install
npm install -g @alesya_h/jsmcp
Or run it without installing globally:
npx @alesya_h/jsmcp
Run
jsmcp
jsmcp work
jsmcp auth
jsmcp auth firefox_devtools
If you are running from a source checkout instead of an installed package, replace jsmcp with node src/index.js.
When running the MCP server, the only optional argument is the preset name. If omitted, default is used.
Use jsmcp auth to manage OAuth for remote servers. With no arguments it lists remote servers that have OAuth enabled. With a server name it starts the OAuth flow for that server.
If no graphical environment is detected, or if you pass --no-browser, jsmcp auth <server> prints the authorization URL and waits for either the localhost callback or a pasted callback URL/code.
Config
The config file may be JSON or YAML and uses these top-level keys:
servers: server definitionspresets: optional overrides for which servers and tools are exposed to the agent
Server names must be valid JavaScript identifiers because execute_code() exposes them directly as globals.
jsmcp accepts both OpenCode MCP config style and the overlapping Claude Code MCP style for the common fields:
- local servers:
type: "local"ortype: "stdio" - remote servers:
type: "remote",type: "http", ortype: "sse" - commands: either
command: ["cmd", "arg1"]orcommand: "cmd"withargs: ["arg1"] - environment variables: either
environmentorenv
Supported servers.<name> fields:
type: required; one oflocal,stdio,remote,http,ssedescription: optional string shown inlist_servers()enabled: optional boolean; defaults totruetimeout: optional number in milliseconds used for initial tool discovery
For local / stdio servers:
command: required; non-empty string or non-empty arrayargs: optional array; appended tocommandwhencommandis a string, and also accepted whencommandis an arrayenv: optional object of environment variablesenvironment: optional object of environment variables; merged withenv, and wins on duplicate keyscwd: optional working directory
For remote / HTTP / SSE servers:
url: required stringheaders: optional object of request headersoauth: optional OAuth config
Supported oauth forms:
- omitted,
null, ortrue: enable OAuth with default behavior false: disable OAuth for that server- object with any of:
clientIdclientSecretscope
Supported value substitutions in string fields:
{env:NAME}: expand from the current environment${NAME}: Claude Code-style environment expansion${NAME:-default}: Claude Code-style expansion with fallback{file:path}: replace with file contents
For {file:path}:
- relative paths are resolved relative to the config file directory
~/...resolves from the user home directory- absolute paths are used as-is
If presets is omitted, the default preset includes every server with enabled !== false and allows all of that server's tools.
If presets is present, it is an object of preset names. Each preset is an object of per-server overrides layered on top of the server definitions:
presets.default: optional overrides for the default preset- any other preset name, such as
presets.work: additional named preset overrides
Within a preset, server rules work like this:
- omitted server rule: use the server definition as-is
true: include that server and allow all its toolsfalse: exclude that server from that preset"tool_name": include only that exact tool- array entries may be:
- exact tool name strings
{ "regex": "..." }selectors{ "glob": "..." }selectors
If a server has enabled: false in servers, adding it to a preset enables it for that preset.
Example:
{
"servers": {
"math": {
"type": "stdio",
"description": "Basic arithmetic tools",
"command": "node",
"args": ["/absolute/path/to/math-server.js"],
"env": {
"LOG_LEVEL": "debug"
},
"cwd": "${PWD}"
},
"docs": {
"type": "http",
"description": "Documentation search and retrieval",
"url": "https://example.com/mcp",
"headers": {
"Authorization": "Bearer ${DOCS_TOKEN}"
},
"oauth": {
"scope": "docs.read"
}
}
},
"presets": {
"default": {
"math": ["add", { "glob": "mul_*" }],
"docs": [{ "regex": "(search|fetch)" }]
},
"work": {
"docs": true
}
}
}
Compatibility notes:
- Claude Code-style
env,type: "stdio",type: "http",type: "sse", andcommandplusargsare supported - OpenCode-style
type: "local",type: "remote", command arrays, andenvironmentare also supported - Claude Code-specific features such as
headersHelperand advanced OAuth fields likecallbackPortorauthServerMetadataUrlare not supported yet
OAuth tokens and registration state are stored in $XDG_DATA_HOME/jsmcp/oauth.json or ~/.local/share/jsmcp/oauth.json.
Exposed Tools
list_serverslist_toolsexecute_codefetch_logsclear_logs
Behavior
- servers in the default preset are started when
jsmcpstarts list_servers()is the required first step so the agent can learn what capabilities are available- you must call
list_tools(server)before using a server inexecute_code()so you know the exact tool names, aliases, and schemas list_tools(server)returns only the tools allowed for that server in the presetexecute_code(code)does not manage server lifecycle; it can only use servers that are already started- prefer
execute_code(code)whenever the work would require more than a single tool call console.log,console.info,console.warn, andconsole.errorinsideexecute_code()are stored forfetch_logs()fetch_logs()drains the log buffer on read
execute_code
execute_code runs JavaScript as the body of an async function.
Started servers are injected as globals. Each allowed MCP tool becomes a function on that server object. Prefer underscore aliases when available.
You should call list_tools(server) before using a server in execute_code(). For multi-step work, prefer writing JavaScript instead of trying to mentally chain several tool calls.
Example:
return await math.add({ a: 2, b: 5 });
If the MCP tool returns structuredContent, that is what the JavaScript call resolves to. So the example above can return:
{
"sum": 7
}
If a tool name is not a valid JavaScript identifier, prefer its underscore alias:
return await math.tool_name({ value: 1 });
The original tool name still works with bracket access:
return await math["tool-name"]({ value: 1 });
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.