Introduction
If you’re using ClaudeMind in your IntelliJ-based IDE (JetBrains family), you might want to avoid sending code to external APIs like Anthropic’s public Claude API. Instead, you can host Claude on AWS Bedrock and expose it locally using FastAPI.
This blog will walk you through:
- Setting up AWS Bedrock to run Claude 3.5 Sonnet.
- Creating a local API proxy using FastAPI that mimics Anthropic’s Claude API.
- Configuring ClaudeMind plugin in IntelliJ to use your local API instead of the public API.
Why use AWS Bedrock instead of Anthropic API?
- Data Privacy: No source code leaves your environment.
- Enterprise-Ready: Works behind corporate firewalls.
- Cost-Efficient: Pay per use instead of monthly subscriptions.
- AI and Cloud: Leveraging AWS for AI-powered application development software.
Step 1: Set Up AWS Bedrock
AWS Bedrock provides access to foundation models like Claude. Follow these steps:
1. Enable AWS Bedrock in Your AWS Account
- Log in to your AWS Console.
- Navigate to AWS Bedrock → Model Access.
- Request access to
anthropic.claude-3-5-sonnet-20240620-v1:0
.
2. Configure AWS CLI for Bedrock
- Ensure you have AWS CLI installed and configured:
aws configure
- Run this to check if your AWS account has access:
aws bedrock list-foundation-models --region us-east-1
- Expected Output:
{ "models": [ { "modelId": "anthropic.claude-3-5-sonnet-20240620-v1:0", "provider": "Anthropic" } ] }
Step 2: Deploy a Local FastAPI Server
We’ll create a FastAPI server that acts as a proxy between ClaudeMind and AWS Bedrock.
1. Install Required Dependencies
pip install fastapi boto3 uvicorn pydantic
2. Create a Python Script
This script:
- Authenticates requests with an API key.
- Formats messages in the correct Claude API format.
- Streams responses from AWS Bedrock back to the plugin.
import json
import uuid
from typing import List, Union, Dict, Any
import boto3
from fastapi import FastAPI, HTTPException, Header, Request
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, field_validator
# Initialize FastAPI App
app = FastAPI()
# AWS Bedrock Client
bedrock_client = boto3.client("bedrock-runtime", region_name="us-east-1")
# API Key for Authentication
API_KEY = "my-secret-api-key"
class Message(BaseModel):
role: str
content: Union[str, List[dict]]
@field_validator("content", mode="before")
def extract_text(cls, value):
if isinstance(value, list) and value and isinstance(value[0], dict) and "text" in value[0]:
return value[0]["text"]
return value
class AnthropicRequest(BaseModel):
model: str
messages: List[Message]
max_tokens: int = 200
temperature: float = 0.7
def process_messages(messages: List[Message]) -> List[Dict[str, str]]:
return [
{
"role": msg.role,
"content": msg.content
}
for msg in messages
]
async def generate_stream_events(streaming_response, message_id: str):
yield 'event: message_start\n'
yield f'''data: {json.dumps({"type": "message_start",
"message": {"id": message_id,
"type": "message",
"role": "assistant",
"content": [],
"model": "claude-3-5-sonnet-20241022",
"stop_reason": None,
"stop_sequence": None,
"usage": {"input_tokens": 0, "output_tokens": 0}}})}\n\n'''
index = 0
for event in streaming_response["body"]:
chunk = json.loads(event["chunk"]["bytes"])
if chunk["type"] == "content_block_delta":
yield f'event: content_block_delta\n'
yield f'''data: {json.dumps({"type": "content_block_delta",
"index": index,
"delta": {"type": "text_delta", "text": chunk["delta"].get("text", "")}})}\n\n'''
elif chunk["type"] == "content_block_stop":
yield f'event: content_block_stop\n'
yield f'data: {json.dumps({"type": "content_block_stop", "index": index})}\n\n'
index += 1
yield 'event: message_stop\n'
yield 'data: {"type": "message_stop"}\n\n'
@app.post("/v1/messages")
async def invoke_claude(request: Request, x_api_key: str = Header(None)):
try:
if x_api_key != API_KEY:
raise HTTPException(status_code=401, detail="Invalid API Key")
body = await request.json()
parsed_request = AnthropicRequest(**body)
processed_messages = process_messages(parsed_request.messages)
message_id = f"msg_{uuid.uuid4().hex}"
bedrock_request = {
"anthropic_version": "bedrock-2023-05-31",
"messages": processed_messages,
"max_tokens": parsed_request.max_tokens,
"temperature": parsed_request.temperature
}
streaming_response = bedrock_client.invoke_model_with_response_stream(
modelId="anthropic.claude-3-5-sonnet-20240620-v1:0",
body=json.dumps(bedrock_request)
)
return StreamingResponse(
generate_stream_events(streaming_response, message_id),
media_type="text/event-stream"
)
except Exception as e:
print("Error:", str(e))
raise HTTPException(status_code=500, detail=str(e))
3. Run the Local Server
uvicorn claude_local_server:app --host 0.0.0.0 --port 8000 --reload
Your Claude API proxy is now running locally!
Step 3: Configure ClaudeMind in IntelliJ
1. Open IntelliJ Settings
- Go to Preferences → Plugins → ClaudeMind.
2. Change Claude API URL
- Default API URL:
https://api.anthropic.com/v1/messages
- Change to:
http://localhost:8000/v1/messages
3. Set API Key
- Use my-secret-api-key (or change it in the script)
Now, ClaudeMind will connect to AWS Bedrock instead of Anthropic!
Step 4: Verify the Setup
1. Open IntelliJ and use ClaudeMind in the IDE.
2. Run a prompt like:
"Can you review this Java method?"
3. Check ClaudeMind’s response to confirm it’s working with AWS Bedrock.
Benefits of This Setup
- Privacy: Code never leaves your network.
- Cost-Efficient: Pay for what you use in AWS Bedrock.
- Enterprise-Friendly: Works in corporate settings with private infrastructure.
- Performance: Low-latency responses from AWS.
- Conversational AI: Enables AI coding agents for enhanced AI software engineering workflows.
Conclusion
By following this guide, you’ve:
- Set up AWS Bedrock to use Claude 3.5 Sonnet.
- Built a FastAPI proxy for ClaudeMind.
- Configured ClaudeMind in IntelliJ to use AWS Bedrock.
Next Steps:
- Host this on EC2 or Docker for team-wide access.