MCP
Connect MCP clients to the ModernLoop broker over Streamable HTTP or local stdio.
MCP
ModernLoop exposes the broker's OpenAPI operations as MCP tools. The production service uses stateless Streamable HTTP.
Before you connect
You need:
-
An MCP client that supports Streamable HTTP.
-
The broker API key in
MLOOP_INTERNAL_MCP_API_KEY. -
The canonical endpoint:
https://api.modernloop.dev/mcp/v1
The key is shared with the REST API. Keep it in your client's secret or environment-variable configuration. Do not commit it to a client configuration file.
The older https://api.modernloop.dev/mcp path is a compatibility alias for the same handler. For
the rest of the broker documentation, see the ModernLoop API docs.
Connection setup
Configure an HTTP MCP client with these values:
| Setting | Value |
|---|---|
| Server URL | https://api.modernloop.dev/mcp/v1 |
| Transport | Streamable HTTP |
| Authorization | Bearer $MLOOP_INTERNAL_MCP_API_KEY |
| Accept | application/json, text/event-stream |
| Content-Type | application/json for JSON-RPC requests |
The endpoint accepts GET, POST, and DELETE at the application route. MCP protocol messages
use POST; clients should manage the transport details after connecting.
Codex
In Codex, export the broker key before starting Codex:
export MLOOP_INTERNAL_MCP_API_KEY='your-broker-key'Add this server entry to ~/.codex/config.toml:
[mcp_servers.modernloop]
url = "https://api.modernloop.dev/mcp/v1?toolsets=linear,github"
bearer_token_env_var = "MLOOP_INTERNAL_MCP_API_KEY"
default_tools_approval_mode = "writes"default_tools_approval_mode = "writes" controls Codex's client-side approval prompt. It does
not expose write tools on the server. The URL above remains read-only; add &write=true only when
the agent intentionally needs the server to advertise write tools. Restart Codex after changing
config.toml, then run /mcp to verify the connection and available tools. See the Codex MCP
documentation for Codex-specific configuration details.
Initialize
This request uses protocol version 2025-03-26, the version exercised by the repository's MCP
integration tests:
curl -N \
-H "Authorization: Bearer $MLOOP_INTERNAL_MCP_API_KEY" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
https://api.modernloop.dev/mcp/v1 \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"my-client","version":"1.0.0"}}}'Successful initialization returns HTTP 200 with an SSE response. The server is stateless and does
not return an mcp-session-id. After initialization, the client can request tools/list and call
tools with tools/call.
Endpoint options
Append query parameters to either /mcp/v1 or the compatibility /mcp path. The options combine
with &:
| Option | Accepted values | Effect |
|---|---|---|
toolsets | Omitted or all | Exposes all current toolsets. This gives the client more tools and consumes more context. |
toolsets | Comma-separated names, such as linear,github | Exposes only the selected toolsets. Select only the services the agent needs. |
write | Omitted or false | Read-only mode. Operations marked x-write: true are hidden. |
write | Bare write or write=true | Includes operations marked x-write: true. |
Recommended starting point:
https://api.modernloop.dev/mcp/v1?toolsets=linear,githubTo enable writes for those toolsets, combine the options with an ampersand:
https://api.modernloop.dev/mcp/v1?toolsets=linear,github&write=trueOmitting toolsets or using toolsets=all exposes all current toolsets. That may be convenient for
exploration, but it increases the tool list and the context an MCP client must manage. Prefer an
explicit, narrow selection for production agents.
Invalid or repeated parameters return HTTP 400 with JSON-RPC error code -32602. Examples include
an unknown toolset, an empty toolset name, toolsets=all,linear, write=1, write=TRUE, or repeated
parameters such as write=true&write=false. Names within one comma-separated toolsets value are
trimmed and de-duplicated; repeating the query parameter itself is invalid.
Available toolsets
The current operation counts come from the committed OpenAPI document. Counts include both read and write operations; the default connection exposes only the read subset.
| Toolset | Operations | What it covers |
|---|---|---|
cursor | 27 | Cursor agents, agent runs, team administration, analytics, and code tracking. |
datadog | 14 | Logs, spans, RUM events, applications, and log indexes. |
db | 1 | Broker database SQL queries. |
firecrawl | 3 | Web scraping, search, and site mapping. |
github | 21 | Repository pull requests, issues, reviews, branches, search, REST, and GraphQL. |
gong | 24 | Calls, transcripts, users, activity, settings, Engage, and tasks. |
google-calendar | 8 | Calendars, events, and free/busy lookup. |
launchdarkly | 16 | Feature flags, environments, projects, targeting, and native API access. |
linear | 1 | Linear's provider-native GraphQL endpoint. |
meta | 1 | Broker health information. |
notion | 35 | Search, pages, blocks, databases, data sources, comments, users, and file uploads. |
posthog | 3 | Project metadata and logs queries. |
pylon | 42 | Accounts, issues, contacts, users, teams, tags, custom fields, and messages. |
render | 48 | Render environments, services, deploys, jobs, logs, metrics, projects, and maintenance. |
sendgrid | 22 | Mail, templates, contacts, suppressions, statistics, validation, and account data. |
sentry | 7 | Projects, issues, issue events, and Sentry API requests. |
slack | 11 | Channels, history, threads, users, message search, messages, and reactions. |
The list is derived from OpenAPI tags, so new operations or services can change the available toolsets and counts.
Tool behavior
Names and arguments
Each tool name is the OpenAPI operationId, unchanged. Examples include:
github_getPullRequestgithub_listPullRequestslinear_graphqlslack_searchMessages
Path and query parameters become top-level tool arguments. A JSON request body is passed under
body. For example, this tools/call request invokes github_getPullRequest:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "github_getPullRequest",
"arguments": {
"owner": "ModernLoop",
"repo": "mloop-internal",
"number": 1
}
}
}The corresponding broker request is:
GET https://api.modernloop.dev/rest/v1/github/repos/ModernLoop/mloop-internal/pulls/1For a body-bearing operation, pass the JSON payload under body. Path values are URL-encoded and
provided query values use the serialization rules from the OpenAPI document.
Read and write behavior
Operations marked x-write: true are excluded unless write is enabled. The MCP tool annotations
also identify reads with readOnlyHint: true and writes with destructiveHint: true.
Tool calls return one text content item containing pretty-printed JSON. A non-2xx broker response is
returned as MCP content with isError: true, preserving the broker's error envelope.
Compact examples
| Goal | Example |
|---|---|
| Connect with only read tools for Linear and GitHub | https://api.modernloop.dev/mcp/v1?toolsets=linear,github |
| Connect with Linear and GitHub writes enabled | https://api.modernloop.dev/mcp/v1?toolsets=linear,github&write=true |
| List every read tool | POST https://api.modernloop.dev/mcp/v1 with a tools/list JSON-RPC request |
| List every tool, including writes | POST https://api.modernloop.dev/mcp/v1?toolsets=all&write=true with tools/list |
| Inspect the REST contract | GET https://api.modernloop.dev/rest/v1/openapi.json |
| Open the human documentation | https://api.modernloop.dev/docs |
Local stdio
Use the generated stdio server for editor integrations that do not support Streamable HTTP:
pnpm --filter @v2/mcp build
V2_API_BASE_URL=https://api.modernloop.dev \
MLOOP_INTERNAL_MCP_API_KEY="$MLOOP_INTERNAL_MCP_API_KEY" \
pnpm --filter @v2/mcp exec v2-mcp --toolsets linearAdd --write only when the local server should expose write tools. Use --remote-spec to load the
OpenAPI document from https://api.modernloop.dev/rest/v1/openapi.json at startup. The CLI defaults
to the local broker at http://localhost:10001 when V2_API_BASE_URL is not set.
Validate the connection
Use this sequence when testing a new client:
- Send
initializeand confirm HTTP200and an SSE response. - Call
tools/listand confirm the selected toolset is present. - Confirm a read tool is listed without
write. - Add
write=trueonly when needed and confirm the expected write tool appears. - Call a read tool with the argument shape shown above.
The repository tests cover authentication, initialization, stateless behavior, tool filtering, write gating, invalid query parameters, tool derivation, URL construction, request bodies, and error mapping.
Troubleshooting
- 401 Unauthorized: check the
Authorization: Bearer <key>header, including theBearerprefix, and verify that the key matchesMLOOP_INTERNAL_MCP_API_KEY. - 500
SERVER_MISCONFIGURED: the broker process does not haveMLOOP_INTERNAL_MCP_API_KEYconfigured. - 400
-32602for endpoint options: check for unknown or empty toolset names, repeated query parameters,allcombined with another toolset, or invalid write values. Use&betweentoolsetsandwrite. - A write tool is missing: writes are hidden unless the URL includes
write=trueor barewrite. Also check that the relevant toolset is selected. - A tool call returns
isError: true: inspect the text content for the broker error envelope. The broker also applies a 30-second request timeout and returnsREQUEST_TIMEOUTwith HTTP504. - The client sees too many tools: narrow
toolsetsto the services required for the task.