Skip to content

Commit cf23a3f

Browse files
authored
Merge pull request #46 from schemacrawler/mcpserver
Create a new plugin to start the SchemaCrawler MCP server
2 parents 82727fd + c8c6a0f commit cf23a3f

File tree

12 files changed

+478
-68
lines changed

12 files changed

+478
-68
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package schemacrawler.tools.command.aichat.mcp;
2+
3+
import schemacrawler.schema.Catalog;
4+
5+
import java.sql.Connection;
6+
7+
import static java.util.Objects.requireNonNull;
8+
9+
/**
10+
* A singleton service that provides access to database connection resources. This class follows an
11+
* initialization-on-demand pattern where the service must be explicitly initialized once before it
12+
* can be used.
13+
*/
14+
public class ConnectionService {
15+
16+
private static final Object lock = new Object();
17+
private static volatile ConnectionService connectionService;
18+
private final Catalog catalog;
19+
private final Connection connection;
20+
private final McpServerCommandOptions options;
21+
22+
/**
23+
* Private constructor to prevent direct instantiation. Use {@link
24+
* #instantiate(McpServerCommandOptions, Catalog, Connection)} to initialize and {@link
25+
* #getInstance()} to access the singleton instance.
26+
*/
27+
private ConnectionService(
28+
final McpServerCommandOptions options, final Catalog catalog, final Connection connection) {
29+
this.catalog = requireNonNull(catalog, "No catalog provided");
30+
this.connection = requireNonNull(connection, "No connection provided");
31+
this.options = requireNonNull(options, "No options provided");
32+
}
33+
34+
/**
35+
* Initializes the ConnectionService singleton. This method should be called exactly once during
36+
* application startup. Subsequent calls will throw an IllegalStateException.
37+
*
38+
* @param options Command options
39+
* @param catalog Database schema catalog
40+
* @param connection SQL connection
41+
* @throws IllegalStateException if the service has already been initialized
42+
*/
43+
public static void instantiate(
44+
final McpServerCommandOptions options, final Catalog catalog, final Connection connection) {
45+
synchronized (lock) {
46+
if (connectionService != null) {
47+
throw new IllegalStateException("ConnectionService has already been initialized");
48+
}
49+
connectionService = new ConnectionService(options, catalog, connection);
50+
}
51+
}
52+
53+
/**
54+
* Gets the singleton instance of ConnectionService. The service must have been initialized with
55+
* {@link #instantiate(McpServerCommandOptions, Catalog, Connection)} before this method is
56+
* called.
57+
*
58+
* @return The singleton ConnectionService instance
59+
* @throws IllegalStateException if the service has not been initialized
60+
*/
61+
public static ConnectionService getInstance() {
62+
if (connectionService == null) {
63+
throw new IllegalStateException("ConnectionService has not been initialized yet");
64+
}
65+
return connectionService;
66+
}
67+
68+
public Catalog catalog() {
69+
return catalog;
70+
}
71+
72+
public Connection connection() {
73+
return connection;
74+
}
75+
76+
public McpServerCommandOptions options() {
77+
return options;
78+
}
79+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
========================================================================
3+
SchemaCrawler
4+
http://www.schemacrawler.com
5+
Copyright (c) 2000-2025, Sualeh Fatehi <sualeh@hotmail.com>.
6+
All rights reserved.
7+
------------------------------------------------------------------------
8+
9+
SchemaCrawler is distributed in the hope that it will be useful, but
10+
WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
13+
SchemaCrawler and the accompanying materials are made available under
14+
the terms of the Eclipse Public License v1.0, GNU General Public License
15+
v3 or GNU Lesser General Public License v3.
16+
17+
You may elect to redistribute this code under any of these licenses.
18+
19+
The Eclipse Public License is available at:
20+
http://www.eclipse.org/legal/epl-v10.html
21+
22+
The GNU General Public License v3 and the GNU Lesser General Public
23+
License v3 are available at:
24+
http://www.gnu.org/licenses/
25+
26+
========================================================================
27+
*/
28+
29+
package schemacrawler.tools.command.aichat.mcp;
30+
31+
import schemacrawler.tools.executable.BaseSchemaCrawlerCommand;
32+
import us.fatehi.utility.property.PropertyName;
33+
34+
import java.util.logging.Level;
35+
import java.util.logging.Logger;
36+
37+
/** SchemaCrawler command plug-in. */
38+
public final class McpServerCommand extends BaseSchemaCrawlerCommand<McpServerCommandOptions> {
39+
40+
private static final Logger LOGGER = Logger.getLogger(McpServerCommand.class.getName());
41+
42+
static final PropertyName COMMAND =
43+
new PropertyName("mcpserver", "Allow AI agents access to your schema");
44+
45+
protected McpServerCommand() {
46+
super(COMMAND);
47+
}
48+
49+
@Override
50+
public void checkAvailability() throws RuntimeException {
51+
LOGGER.log(Level.FINE, "No checks required for MCP server");
52+
}
53+
54+
@Override
55+
public void execute() {
56+
LOGGER.log(Level.FINE, "Starting MCP server");
57+
ConnectionService.instantiate(commandOptions, catalog, connection);
58+
SchemaCrawlerMcpServer.start();
59+
}
60+
61+
@Override
62+
public boolean usesConnection() {
63+
// Support commands that use connections
64+
return true;
65+
}
66+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
========================================================================
3+
SchemaCrawler
4+
http://www.schemacrawler.com
5+
Copyright (c) 2000-2025, Sualeh Fatehi <sualeh@hotmail.com>.
6+
All rights reserved.
7+
------------------------------------------------------------------------
8+
9+
SchemaCrawler is distributed in the hope that it will be useful, but
10+
WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
13+
SchemaCrawler and the accompanying materials are made available under
14+
the terms of the Eclipse Public License v1.0, GNU General Public License
15+
v3 or GNU Lesser General Public License v3.
16+
17+
You may elect to redistribute this code under any of these licenses.
18+
19+
The Eclipse Public License is available at:
20+
http://www.eclipse.org/legal/epl-v10.html
21+
22+
The GNU General Public License v3 and the GNU Lesser General Public
23+
License v3 are available at:
24+
http://www.gnu.org/licenses/
25+
26+
========================================================================
27+
*/
28+
29+
package schemacrawler.tools.command.aichat.mcp;
30+
31+
import schemacrawler.tools.executable.CommandOptions;
32+
33+
34+
public record McpServerCommandOptions() implements CommandOptions {
35+
36+
public McpServerCommandOptions {
37+
// No options for this command
38+
}
39+
40+
@Override
41+
public String toString() {
42+
// No options for this command
43+
return this.getClass().getName();
44+
}
45+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
========================================================================
3+
SchemaCrawler
4+
http://www.schemacrawler.com
5+
Copyright (c) 2000-2025, Sualeh Fatehi <sualeh@hotmail.com>.
6+
All rights reserved.
7+
------------------------------------------------------------------------
8+
9+
SchemaCrawler is distributed in the hope that it will be useful, but
10+
WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
13+
SchemaCrawler and the accompanying materials are made available under
14+
the terms of the Eclipse Public License v1.0, GNU General Public License
15+
v3 or GNU Lesser General Public License v3.
16+
17+
You may elect to redistribute this code under any of these licenses.
18+
19+
The Eclipse Public License is available at:
20+
http://www.eclipse.org/legal/epl-v10.html
21+
22+
The GNU General Public License v3 and the GNU Lesser General Public
23+
License v3 are available at:
24+
http://www.gnu.org/licenses/
25+
26+
========================================================================
27+
*/
28+
29+
package schemacrawler.tools.command.aichat.mcp;
30+
31+
import schemacrawler.schemacrawler.OptionsBuilder;
32+
import schemacrawler.tools.options.Config;
33+
import schemacrawler.tools.options.ConfigOptionsBuilder;
34+
35+
36+
public final class McpServerCommandOptionsBuilder
37+
implements OptionsBuilder<McpServerCommandOptionsBuilder, McpServerCommandOptions>,
38+
ConfigOptionsBuilder<McpServerCommandOptionsBuilder, McpServerCommandOptions> {
39+
40+
public static McpServerCommandOptionsBuilder builder() {
41+
return new McpServerCommandOptionsBuilder();
42+
}
43+
44+
private McpServerCommandOptionsBuilder() {
45+
// No options for this command
46+
}
47+
48+
@Override
49+
public McpServerCommandOptionsBuilder fromConfig(final Config config) {
50+
// No options for this command
51+
return this;
52+
}
53+
54+
@Override
55+
public McpServerCommandOptionsBuilder fromOptions(final McpServerCommandOptions options) {
56+
// No options for this command
57+
return this;
58+
}
59+
60+
@Override
61+
public Config toConfig() {
62+
// No options for this command
63+
return new Config();
64+
}
65+
66+
@Override
67+
public McpServerCommandOptions toOptions() {
68+
return new McpServerCommandOptions();
69+
}
70+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
========================================================================
3+
SchemaCrawler
4+
http://www.schemacrawler.com
5+
Copyright (c) 2000-2025, Sualeh Fatehi <sualeh@hotmail.com>.
6+
All rights reserved.
7+
------------------------------------------------------------------------
8+
9+
SchemaCrawler is distributed in the hope that it will be useful, but
10+
WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
13+
SchemaCrawler and the accompanying materials are made available under
14+
the terms of the Eclipse Public License v1.0, GNU General Public License
15+
v3 or GNU Lesser General Public License v3.
16+
17+
You may elect to redistribute this code under any of these licenses.
18+
19+
The Eclipse Public License is available at:
20+
http://www.eclipse.org/legal/epl-v10.html
21+
22+
The GNU General Public License v3 and the GNU Lesser General Public
23+
License v3 are available at:
24+
http://www.gnu.org/licenses/
25+
26+
========================================================================
27+
*/
28+
29+
package schemacrawler.tools.command.aichat.mcp;
30+
31+
import static schemacrawler.tools.executable.commandline.PluginCommand.newPluginCommand;
32+
import schemacrawler.schemacrawler.exceptions.ExecutionRuntimeException;
33+
import schemacrawler.tools.executable.BaseCommandProvider;
34+
import schemacrawler.tools.executable.commandline.PluginCommand;
35+
import schemacrawler.tools.options.Config;
36+
import schemacrawler.tools.options.OutputOptions;
37+
38+
/** SchemaCrawler command plug-in for AI chat. */
39+
public final class McpServerCommandProvider extends BaseCommandProvider {
40+
41+
public McpServerCommandProvider() {
42+
super(McpServerCommand.COMMAND);
43+
}
44+
45+
@Override
46+
public PluginCommand getCommandLineCommand() {
47+
final PluginCommand pluginCommand = newPluginCommand(McpServerCommand.COMMAND);
48+
return pluginCommand;
49+
}
50+
51+
@Override
52+
public McpServerCommand newSchemaCrawlerCommand(final String command, final Config config) {
53+
if (!supportsCommand(command)) {
54+
throw new IllegalArgumentException("Cannot support command, " + command);
55+
}
56+
57+
try {
58+
final McpServerCommandOptions options =
59+
McpServerCommandOptionsBuilder.builder().fromConfig(config).toOptions();
60+
61+
final McpServerCommand scCommand = new McpServerCommand();
62+
scCommand.configure(options);
63+
return scCommand;
64+
} catch (final Exception e) {
65+
throw new ExecutionRuntimeException(e);
66+
}
67+
}
68+
69+
@Override
70+
public boolean supportsOutputFormat(final String command, final OutputOptions outputOptions) {
71+
return true;
72+
}
73+
}

schemacrawler-ai-mcp/src/main/java/schemacrawler/tools/command/aichat/mcp/SchemaCrawlerMCPServer.java

Lines changed: 0 additions & 36 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package schemacrawler.tools.command.aichat.mcp;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
7+
8+
/**
9+
* Spring Boot application for the SchemaCrawler AI MCP server. This class enables the Spring AI MCP
10+
* server capabilities.
11+
*/
12+
@SpringBootApplication
13+
public class SchemaCrawlerMcpServer {
14+
15+
public static void main(final String[] args) {
16+
SpringAIUtility.isDryRun = true;
17+
start();
18+
}
19+
20+
public static void start() {
21+
SpringApplication.run(SchemaCrawlerMcpServer.class);
22+
}
23+
}

0 commit comments

Comments
 (0)