Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/mcp-bounded-transport-and-e2e-402.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"lens": minor
---

Enforce bounded tool results, streamable HTTP transport with authentication, and deterministic end-to-end 402 loop verification on Bazaar MCP server:
- Bounded tool results with configurable `maxResultBytes` limit (`MCP_MAX_RESULT_BYTES`), dropping pretty-printing to prevent agent context window inflation (#416).
- Explicit truncation notifications (`[TRUNCATED: Result exceeded limit...]`) and collections pagination for `bazaar_search` results (#416).
- Streaming reader (`readBoundedResponseBody`) aborts oversized upstream payloads upon reaching `maxUpstreamBytes` without buffering excessive bytes in memory (#416).
- Supported streamable HTTP transport alongside default stdio transport (`MCP_TRANSPORT=http`), requiring authentication via `MCP_API_KEY` with `401 Unauthorized` refusal on missing or invalid keys (#419).
- Documented stdio and HTTP transport execution in `README.md` (#419).
- End-to-end deterministic integration test verifying successful 402 payment loops against stubbed facilitators, asserting signed amount, destination address, and testnet network using in-memory ephemeral testnet keypairs (#423).
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,41 @@ curl -s http://localhost:3002/price/XLM/USDC | jq '{price, ammPrice, lastUpdated
| `ORACLE_PAYMENT_ADDRESS_TESTNET` / `ORACLE_PAYMENT_ADDRESS_MAINNET` | Per-network override for the address above | - | No |
| `X402_FACILITATOR_URL` | x402 facilitator service URL | - | No |

*\*Required if enabling x402 payment gating.*
## MCP Server (Model Context Protocol)

Lens provides a Model Context Protocol (MCP) server exposing tools for Stellar resource discovery and automated paid calls (`bazaar_search`, `paid_call`).

### Running via Stdio (Default)

For locally-launched agent processes (e.g. Claude Desktop, local coding agents, or CLI child processes):

```bash
npm run mcp:server
```

Stdio is the default transport (`MCP_TRANSPORT=stdio`). It communicates over standard input/output streams.

### Running via Streamable HTTP Transport

For hosted Lens instances serving remote agents over the network, configure the HTTP transport and specify a mandatory authentication key:

```bash
MCP_TRANSPORT=http MCP_PORT=3000 MCP_API_KEY=your-secret-key npm run mcp:server
```

> **Authentication Requirement**: Remote HTTP exposure strictly requires authentication via `Authorization: Bearer <key>` or `x-api-key: <key>`. Unauthenticated requests are immediately refused with `401 Unauthorized` to protect funds and resources.

### MCP Configuration

| Variable | Description | Default |
|---|---|---|
| `MCP_TRANSPORT` | Transport protocol (`stdio` or `http`) | `stdio` |
| `MCP_PORT` | Port for HTTP transport | `3000` |
| `MCP_HOST` | Host address for HTTP transport | `127.0.0.1` |
| `MCP_API_KEY` | Mandatory API authentication key for HTTP transport | - |
| `MCP_MAX_RESULT_BYTES` | Maximum byte length per tool result before explicit truncation | `65536` (64 KB) |
| `MCP_MAX_UPSTREAM_BYTES` | Maximum upstream response stream buffering limit before stream cancel | `131072` (128 KB) |
| `MCP_MAX_PAYMENT_PRICE` | Maximum allowed price per single `paid_call` execution | `$1.00` |

## Stack
- **Runtime:** Node.js 20 + TypeScript
Expand Down
13 changes: 11 additions & 2 deletions examples/mcp-server/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,21 @@ async function main() {
.map(entry => entry.trim())
.filter(Boolean);

const transport = process.env.MCP_TRANSPORT === 'http' ? 'http' : 'stdio';
const server = new BazaarMcpServer({
fetchWithPayment,
paidCallAllowlist
paidCallAllowlist,
transport,
port: process.env.MCP_PORT ? Number(process.env.MCP_PORT) : 3000,
host: process.env.MCP_HOST || '127.0.0.1',
apiKey: process.env.MCP_API_KEY,
});

console.error('[mcp-server] Starting Bazaar MCP server on stdio...');
if (transport === 'http') {
console.error(`[mcp-server] Starting Bazaar MCP server on HTTP (port ${process.env.MCP_PORT || 3000})...`);
} else {
console.error('[mcp-server] Starting Bazaar MCP server on stdio...');
}
console.error('[mcp-server] Agent configured for stellar:testnet and stellar:pubnet');
console.error(
paidCallAllowlist.length > 0
Expand Down
Loading