Skip to content

Tool Execution

When an LLM returns tool calls in its response, DeepIntShield does not automatically execute them. Instead, your application explicitly calls the tool execution API, giving you full control over:

  • Which tool calls to execute
  • User approval workflows
  • Security validation
  • Audit logging

The basic flow is: Chat Request → Review Tool Calls → Execute Tools → Continue Conversation. For detailed architecture diagrams, see the MCP Architecture documentation.


The /v1/mcp/tool/execute endpoint uses the same authentication as other inference endpoints like /v1/chat/completions:

Auth ConfigurationBehavior
disable_auth_on_inference: trueNo auth required
disable_auth_on_inference: falseAuth required

Virtual keys and authentication are independent layers that work together. For details on how to use virtual keys with authentication, see Authentication and Virtual Keys.


The deepintshield Python SDK exposes a generic shield.mcp surface that works with any MCP server connected to your gateway. It includes adapters for OpenAI, Anthropic, and LangChain.

Terminal window
pip install 'deepintshield[openai]'
from deepintshield import DeepintShield
shield = DeepintShield(
virtual_key="sk-bf-...",
base_url="http://localhost:8080",
)
result = shield.mcp.call(
server="DeepWiki", # case-sensitive client name from MCP Registry
tool="ask_question", # bare tool name; the SDK adds the '<server>-' prefix
repoName="facebook/react",
question="What is Suspense?",
)
print(result.text)
from deepintshield import DeepintShield, Tool
shield = DeepintShield(virtual_key="sk-bf-...", base_url="http://localhost:8080")
openai = shield.openai()
tools = [
Tool(server="DeepWiki", name="ask_question",
description="Ask a question about a public GitHub repository.",
schema={"type": "object",
"properties": {"repoName": {"type": "string"},
"question": {"type": "string"}},
"required": ["repoName", "question"]}),
]
messages = [{"role": "user", "content": "Summarize facebook/react's reconciler."}]
first = openai.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=shield.mcp.to_openai(tools),
tool_choice="required",
)
assistant = first.choices[0].message
messages.append(assistant.model_dump(exclude_none=True))
messages.extend(shield.mcp.run_openai_tool_calls(assistant.tool_calls))
final = openai.chat.completions.create(model="gpt-4o-mini", messages=messages)
print(final.choices[0].message.content)

DeepIntShield supports two API formats for tool execution:

Use ?format=chat or omit the parameter:

Terminal window
POST /v1/mcp/tool/execute?format=chat

Request:

{
"id": "call_xyz789",
"type": "function",
"function": {
"name": "filesystem_read_file",
"arguments": "{\"path\": \"config.json\"}"
}
}

Response:

{
"role": "tool",
"content": "{\"key\": \"value\"}",
"tool_call_id": "call_xyz789"
}

Use ?format=responses for the Responses API format:

Terminal window
POST /v1/mcp/tool/execute?format=responses

Request:

{
"type": "function_call_output",
"call_id": "call_xyz789",
"name": "filesystem_read_file",
"arguments": "{\"path\": \"config.json\"}"
}

Response:

{
"type": "function_call_output",
"call_id": "call_xyz789",
"output": "{\"key\": \"value\"}"
}

LLMs often request multiple tools in a single response. Execute them in sequence or parallel:

for _, toolCall := range *response.Choices[0].Message.ToolCalls {
result, err := client.ExecuteChatMCPTool(ctx, toolCall)
if err != nil {
// Handle error
continue
}
history = append(history, *result)
}

Tool execution can fail for various reasons:

result, err := client.ExecuteChatMCPTool(ctx, toolCall)
if err != nil {
switch {
case errors.Is(err, context.DeadlineExceeded):
// Tool execution timed out
case strings.Contains(err.Error(), "tool not found"):
// Tool doesn't exist or client disconnected
case strings.Contains(err.Error(), "not allowed"):
// Tool filtered out by configuration
default:
// Other execution error
}
}

Gateway error responses:

{
"error": {
"type": "tool_execution_error",
"message": "Tool 'filesystem_delete_file' is not allowed for this request"
}
}

Tool execution responses are designed to be directly appended to your conversation history:

// Tool result is already in the correct format
toolResult, _ := client.ExecuteChatMCPTool(ctx, toolCall)
// Just append it directly
history = append(history, *toolResult)

The response includes:

  • Correct role field ("tool")
  • Matching tool_call_id for correlation
  • Properly formatted content

Agent Mode

Enable autonomous tool execution with auto-approval

Open →

Tool Filtering

Control which tools are available per request

Open →