PortalMCP
by PortalFnd
README.md
<div align="center">
# π PortalMCP
### Universal AI gateway to Ethereum
**One server. Every AI. The whole chain.**
Plug any Model-Context-Protocol client β Claude, ChatGPT, Gemini, Cursor, Windsurf, Cline, custom agents β into Ethereum with natural language. Check balances, swap tokens, mint NFTs, generate and deploy smart contracts.
[](https://github.com/modelcontextprotocol/typescript-sdk)
[](https://docs.ethers.org/v6/)
[](https://www.typescriptlang.org/)
[](./LICENSE)
[](./CHANGELOG.md)
[**Quick start**](#-quick-start) Β· [**Setup**](#-client-setup) Β· [**Tools**](#-what-it-can-do) Β· [**Roadmap**](./ROADMAP.md) Β· [**Changelog**](./CHANGELOG.md)
</div>
---
## β¨ Why PortalMCP
Most AI-blockchain integrations lock you to one LLM or one client. PortalMCP is a spec-compliant **MCP server** β the same server, running locally or on your VPS, powers every MCP-capable client.
> π **Non-custodial** β private keys never leave your machine
> π°οΈ **Live chain context** β resources stream ETH balances, tx receipts and token metadata straight into your chat
> π‘οΈ **Safety-first** β every tool declares read/destructive/idempotent hints so clients can confirm before broadcasting
> π§© **Universal** β works over both stdio and HTTP, plays with every MCP client out there
---
## π§ Compatible clients
| Client | Transport | Notes |
|---|---|---|
| π£ **Claude Desktop** (macOS/Windows) | stdio | Drop-in config below |
| π **Claude.ai web + mobile** | HTTP | Add as *Custom Connector* (Pro/Team/Enterprise) |
| π» **Claude Code / CLI** | either | |
| π§ **Cursor Β· Windsurf Β· Cline Β· Continue Β· Zed AI** | stdio | Native MCP |
| π¬ **ChatGPT** (Team/Enterprise) | HTTP | MCP connector |
| π οΈ **ChatGPT Custom GPTs** | REST | Uses bundled `openapi.json` |
| β΄οΈ **Google Gemini / Vertex Agents** | HTTP | MCP connector |
| π **LangChain Β· LlamaIndex Β· OpenAI Agents SDK** | either | via their MCP adapters |
| π€ **Any HTTP agent** | HTTP | Plain JSON-RPC + SSE on `/mcp` |
---
## π― What it can do
<details open>
<summary><b>17 tools</b> β click to expand</summary>
#### β‘ General
| Tool | Action |
|---|---|
| `eth_get_balance` | ETH balance of any address or the default wallet |
| `eth_call_contract` | Read-only call against any contract + ABI |
| `eth_send_transaction` | Prepare a generic unsigned transaction |
#### π Smart contracts
| Tool | Action |
|---|---|
| `eth_generate_contract` | Claude-authored Solidity from natural language |
| `eth_compile_contract` | solc compile β bytecode + ABI |
| `eth_deploy_contract` | Prepare deployment tx for external wallet signing |
| `eth_deploy_contract_with_signer` | Deploy directly using `DEPLOYER_PRIVATE_KEY` |
#### πͺ ERC-20 tokens
| Tool | Action |
|---|---|
| `eth_create_token` | Generate ERC-20 Solidity |
| `eth_get_token_balance` | ERC-20 balance of any holder |
| `eth_transfer_token` | Signed transfer or unsigned-tx prep |
#### πΌοΈ ERC-721 NFTs
| Tool | Action |
|---|---|
| `eth_create_nft_collection` | Generate ERC-721 Solidity |
| `eth_mint_nft` | Prepare `mint` / `safeMint` / `mintWithURI` |
| `eth_get_nft_owner` | `ownerOf()` lookup |
#### π¦ DeFi
| Tool | Action |
|---|---|
| `eth_create_staking_contract` | Generate staking Solidity |
| `eth_stake_tokens` | Prepare approve + stake txs |
| `eth_swap_tokens` | Universal Uniswap V3 swap (any ERC-20 pair) |
| `eth_swap_eth_to_usdt` | Convenience alias of the above |
</details>
<details>
<summary><b>4 resources</b> (live chain data as context)</summary>
| URI | Returns |
|---|---|
| `eth://wallet` | Configured signer address, network, ETH balance |
| `eth://balance/{address}` | Live ETH balance for any address |
| `eth://tx/{hash}` | Transaction + receipt (status, gas, block, logs, explorer URL) |
| `eth://token/{address}` | ERC-20 metadata (name, symbol, decimals, total supply) |
</details>
<details>
<summary><b>2 prompts</b> (slash commands)</summary>
- `/swap_tokens` β guided token-swap flow
- `/deploy_erc20` β generate β compile β deploy end-to-end
</details>
---
## π Quick start
```bash
git clone https://github.com/PortalFnd/PortalMCP.git
cd PortalMCP/portalmcp
npm install
cp .env.example .env
# fill in .env β ANTHROPIC_API_KEY, DEPLOYER_PRIVATE_KEY,
# and ETHEREUM_RPC_URL (or a real ALCHEMY_API_KEY)
npm run build
npm run smoke # β 17 tools / 1 resource / 3 templates / 2 prompts
npm start # stdio (Claude Desktop, Cursor, β¦)
# or
npm run start:http # Streamable HTTP on http://0.0.0.0:3333/mcp
```
---
## π Client setup
<details open>
<summary><b>π£ Claude Desktop</b> (stdio)</summary>
<br>
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
```json
{
"mcpServers": {
"portalmcp": {
"command": "node",
"args": ["/absolute/path/to/PortalMCP/portalmcp/dist/index.js"],
"env": {
"ETHEREUM_NETWORK": "mainnet",
"ETHEREUM_RPC_URL": "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY",
"DEPLOYER_PRIVATE_KEY": "0x...",
"ANTHROPIC_API_KEY": "sk-ant-..."
}
}
}
}
```
Restart Claude Desktop. 17 tools, `eth://` resources, and two slash commands appear automatically.
</details>
<details>
<summary><b>π Claude.ai web / mobile</b> (Streamable HTTP)</summary>
<br>
1. Host the HTTP server with a public HTTPS URL (Caddy / Cloudflare Tunnel / Nginx).
2. Set `MCP_HTTP_TOKEN=<long-random-string>` so only you can call it.
3. In Claude.ai β **Settings β Connectors β Add Custom Connector**:
- **URL:** `https://your-host.example.com/mcp`
- **Auth:** `Authorization: Bearer <MCP_HTTP_TOKEN>`
4. Works on both web and the mobile app.
</details>
<details>
<summary><b>π§ Cursor / Windsurf / Cline / Continue</b></summary>
<br>
All speak MCP natively. Add an entry to their MCP config pointing at:
```
node /absolute/path/to/PortalMCP/portalmcp/dist/index.js
```
(Same stdio command as Claude Desktop.)
</details>
<details>
<summary><b>π¬ ChatGPT, Gemini, custom agents</b></summary>
<br>
**Preferred β MCP connector** (ChatGPT Team/Enterprise, Gemini/Vertex Agents):
Point at `https://your-host/mcp`, optionally with a Bearer token.
**Legacy REST** (ChatGPT Custom GPT Actions or any HTTP agent):
```bash
npm run start:api
# OpenAPI spec: http://localhost:3001/openapi.json
```
</details>
---
## π¬ Example conversations
> **Deploy a token from scratch**
>
> *"Deploy an ERC-20 called PortalToken (PRTL) with initial supply 1,000,000."*
>
> β `eth_generate_contract` β shows code β `eth_compile_contract` β `eth_deploy_contract_with_signer` β returns the contract address + Etherscan link.
> **Universal swap**
>
> *"Swap 0.01 ETH for USDC."*
>
> β `eth_swap_tokens { tokenIn:"ETH", tokenOut:"USDC", amount:"0.01" }` β approves (if needed) and executes via Uniswap V3.
> **Live on-chain context**
>
> *"What's the balance of `vitalik.eth`?"*
>
> β client attaches the `eth://balance/0xd8dAβ¦` resource straight into the conversation.
---
## βοΈ Configuration
All via env vars (`.env` file or host env). Full list in `.env.example`.
| Var | Required | Purpose |
|---|:---:|---|
| `ETHEREUM_NETWORK` | β | `mainnet`, `sepolia`, `arbitrum`, `optimism`, `base`, `polygon`, β¦ (default `mainnet`) |
| `ETHEREUM_RPC_URL` | β | Full JSON-RPC URL β overrides Infura/Alchemy key setup |
| `ALCHEMY_API_KEY` | alt | Key only β PortalMCP builds the modern `g.alchemy.com` URL |
| `INFURA_API_KEY` | alt | Infura project ID |
| `DEPLOYER_PRIVATE_KEY` | writes | `0x`-prefixed hex β enables signer-backed tools |
| `ANTHROPIC_API_KEY` | generate | For `eth_generate_contract` |
| `ANTHROPIC_MODEL` | β | Override default `claude-sonnet-4-5-20250929` |
| `MCP_HTTP_PORT` | β | Default `3333` |
| `MCP_HTTP_HOST` | β | Default `0.0.0.0` |
| `MCP_HTTP_TOKEN` | π‘οΈ | Bearer token for the HTTP transport |
| `MCP_HTTP_CORS_ORIGIN` | β | Default `*` |
> π‘ **Placeholder detection** β any env value starting with `your_`, `changeme`, `xxx`, `placeholder`, `<β¦>` is treated as unset. Stops silent misconfigurations dead.
---
## π Networks supported
<table>
<tr><td><b>L1</b></td><td>Ethereum mainnet Β· Sepolia Β· Goerli Β· Holesky</td></tr>
<tr><td><b>L2</b></td><td>Arbitrum Β· Optimism Β· Base Β· Polygon <em>(+ every testnet)</em></td></tr>
<tr><td><b>Custom</b></td><td>Any EVM chain β BSC, Avalanche, Linea, zkSync, β¦ β via <code>ETHEREUM_RPC_URL</code></td></tr>
</table>
---
## π‘οΈ Security
- π« **Never commit `.env`** β already in `.gitignore`.
- π **`DEPLOYER_PRIVATE_KEY` is a loaded gun.** Use a dedicated agent wallet with only funds you can lose.
- π°οΈ **Always set `MCP_HTTP_TOKEN`** when exposing HTTP beyond localhost, and put TLS (Caddy/Cloudflare) in front.
- π§ͺ **Testnet first** β use `sepolia` for development, mainnet only after you've verified the flow.
- π·οΈ **Tool annotations** let clients prompt before destructive txs β don't auto-approve them.
- π **Review generated Solidity** β `eth_generate_contract` is a starting point, not an audit.
---
## π§βπ» Development
```bash
npm install
npm run dev # stdio, ts-node hot-reload
npm run dev:http # HTTP, ts-node
npm run build # tsc β dist/
npm run smoke # assert MCP surface is registered
npm test # Jest
```
| Script | Purpose |
|---|---|
| `npm start` | stdio MCP server (prod) |
| `npm run start:http` | Streamable HTTP MCP server (prod) |
| `npm run start:api` | Legacy REST for ChatGPT Actions / HTTP clients |
| `npm run smoke` | Registration smoke test β great for CI |
### Repo layout
```
portalmcp/
βββ src/
β βββ index.ts # stdio entrypoint
β βββ mcp-http.ts # Streamable HTTP entrypoint
β βββ server-factory.ts # createPortalServer() β shared wiring
β βββ smoke-test.ts # CI registration check
β βββ tools/ # general Β· contracts Β· defi Β· tokens Β· nfts
β βββ blockchain/ # EthereumService Β· CompilerService
β βββ claude/ # ContractGenerator (Anthropic SDK)
β βββ contracts/ # Solidity templates
β βββ adapters/ # Legacy REST / LangChain / OpenAI adapters
βββ dist/ # tsc output
βββ .env.example
βββ package.json
```
---
## ποΈ Architecture
```
stdio Streamable HTTP (SSE)
βββββββββββββββββββββββ βββββββββββββββββββββββββββββββ
β Claude Desktop β β Claude.ai web + mobile β
β Cursor Β· Windsurf β β ChatGPT Β· Gemini β
β Cline Β· Continue β β Custom agents β
βββββββββββ¬ββββββββββββ ββββββββββββββββ¬βββββββββββββββ
β β
β ββββββββββββββββββββββββ β
βββββββββΆβ PortalMCP server βββββββββββββββ
β (server-factory.ts) β
ββββββββββββ¬ββββββββββββ
β
ββββββββββββββββββββββββΌβββββββββββββββββββββββ
βΌ βΌ βΌ
EthereumService Uniswap V3 Anthropic
(ethers v6 + (eth_swap_tokens) (eth_generate_contract)
Alchemy/Infura/
custom RPC)
```
---
## πΊοΈ Roadmap highlights
<table>
<tr>
<td valign="top"><b>Shipped β
</b><br><br>
MCP SDK 1.29 β stdio + HTTP<br>
17 tools Β· 1 resource Β· 3 templates Β· 2 prompts<br>
Tool annotations + outputSchema<br>
Universal Uniswap V3 swap<br>
L1 + L2 + testnets<br>
Anthropic SDK 0.90 Β· Claude Sonnet 4.5<br>
Smoke test for CI
</td>
<td valign="top"><b>Next π</b><br><br>
Elicitation (confirm destructive txs)<br>
ENS / gas helpers<br>
Tx simulation with revert decoding<br>
Multi-DEX aggregation (1inch, 0x)<br>
Aave / Compound read positions<br>
Ledger hardware signer<br>
Gnosis Safe + ERC-4337<br>
Docker + Python SDK
</td>
</tr>
</table>
Full plan in [ROADMAP.md](./ROADMAP.md).
---
## π€ Contributing
PRs welcome! Priority areas: more `outputSchema` coverage, additional tools, Docker packaging, Python client, test coverage. Open an issue first for non-trivial changes.
---
<div align="center">
**[β Star this repo](https://github.com/PortalFnd/PortalMCP)** Β· **[π Report an issue](https://github.com/PortalFnd/PortalMCP/issues)** Β· **[π MIT License](./LICENSE)**
Built with π by the **Portal Foundation**
</div>
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues